简体   繁体   English

如何为C ++项目编写单元测试

[英]How are unit tests written for C++ projects

I am interested in applying unit tests to a growing personal project that I am making in C++. 我有兴趣将单元测试应用于我在C ++中不断发展的个人项目。 I am not formally trained in programming, but instead learned in on my own. 我没有接受过正式的编程培训,而是靠自己学习。 As a result I never really learned how unit testing is typically done in C++. 因此,我从未真正了解单元测试通常是如何在C ++中完成的。 I have read lots and lots of info on the web about why unit testing is important, but I have not had as much luck in finding concrete examples about how unit testing is written into a C++ project. 我在网上看到了很多关于为什么单元测试很重要的信息,但是我没有找到关于如何将单元测试写入C ++项目的具体例子。 What I am currently doing is something like the following: 我目前正在做的事情如下:

I have a special 'Test' class that only contains static methods. 我有一个特殊的'Test'类,它只包含静态方法。 Each method tests one aspect of a class in my project. 每种方法都在我的项目中测试一个类的一个方面。 In concrete code it looks something like: 在具体的代码中,它看起来像:

class Test
{
  public:
    static void test1();
    static void test2();
    static void test3();
};

Then in main I just call: 然后在主要我打电话:

int main()
{
  Test::test1();
  Test::test2();
  Test::test3();
  //etc
}

Each test prints to the console saying whether it passed or not. 每个测试都会打印到控制台,说明它是否通过。 Each test might test my other classes by initializing them, checking their methods for correct outputs, etc... 每个测试都可以通过初始化它们,检查它们的方法以获得正确的输出等来测试我的其他类...

My questions: Is this a standard way of going through unit testing? 我的问题:这是一种经过单元测试的标准方法吗? I have also heard that you write tests directly into each of your classes (so they are just extra methods that happen to do testing). 我还听说你直接在每个类中编写测试(因此它们只是碰巧进行测试的额外方法)。 Then whenever you create an object of a class or call a method it will just run your tests as part of running your program. 然后,无论何时创建类的对象或调用方法,它都只是在运行程序时运行测试。 Is this a better, more standard way, of implementing unit testing? 这是实施单元测试的更好,更标准的方法吗? I am basically just trying to fully understand how exactly unit testing is typically implemented so if some one were to ask me about unit testing I can competently say that I know how to do it. 我基本上只是想彻底了解单元测试通常是如何实现的,所以如果有人问我单元测试,我可以胜任地说我知道怎么做。

My personal experience is that I use Boost.Test. 我个人的经验是我使用Boost.Test。 I use the header only implementation (just a preference). 我只使用标头实现(只是一个偏好)。 It will take you a day or so to read the documentation and start being productive. 您需要一天左右的时间来阅读文档并开始提高工作效率。 The benefit of using a testing library or framework is that you only code and see your tests and not the surrounding code that runs them. 使用测试库或框架的好处是,您只需编写代码并查看测试,而不是运行它们的周围代码。

My strategy, to write tests for a library, for example, is to have a single test file for each class in the library. 例如,我为库编写测试的策略是为库中的每个类创建一个测试文件。 That file has as many test as needed. 该文件根据需要进行了多次测试。 The collection of test files create a separate executable that tests the library. 测试文件集合创建一个单独的可执行文件来测试库。

I would not recommend writing tests directly into your classes. 我不建议将测试直接写入您的课程。 I think it would just clutter you real code. 我认为它会让你真正的代码混乱。

By way of example, here is how I convince myself that my implementations of the SHA-2 suite are still valid. 举例来说,这就是我如何说服自己,我的SHA-2套件的实现仍然有效。 After the SHA code, which is all in one file, there is this 200 lines of validation code at the end which provides a main() to verify. 在SHA代码(全部在一个文件中)之后,最后有200行验证代码,它提供了一个main()来验证。

#ifdef  DBG_SHA2_LIB

/*
 * sha2_lib.cpp main ():  verification and handy hashing program
 *
 * input:
 *  either no arguments (validates against the published test cases)
 *  or a list of filenames with options for which hashes to perform.
 *      sha2_lib -1 -2 -3 -5 filename...
 *
 * output:
 *  messages such as
 *
 *  validating functionality with published examples
 *  sha-160 1(3) okay
 *  sha-160 1(56) okay
 *  sha-160 1000000(1) okay
 *  ...
 *  sha-512 1(112) okay
 *  sha-512 verification failure:  1000000 repeats of "a"
 *  5cff29098832da24 fd1be5644357305c f132f5e100eb1fa0 a0cb6f2c11dfbb4c 36f00d94d4f9
 *  93ad 2eff9f94a9fa2902 92f8982b3bd115d4 f05f67cd0a4db196: computed
 *  e718483d0ce76964 4e2e42c7bc15b463 8e1f98b13b204428 5632a803afa973eb de0ff244877e
 *  a60a 4cb0432ce577c31b eb009c5c2c49aa2e 4eadb217ad8cc09b: expected value
 *
 *  -- or --
 *
 *   * * * File sha2_lib.csm: 0.34 seconds
 *  sha256: e62aec67 d6fd18bd fa700082 547b8733 f6ef2490 61a338b0 6ee82910 2d4e0900
 *
 *  * * * File sha2_lib.exe: 0.01 seconds
 *  sha256: 52a1ea6f 33fefba9 b1d8e039 f9af9fb7 766451b6 675ec5da 7d3db868 d056e3ea
 */

static void
verify (const char *computed, const char *correct, long rpt, const char *inp, int alg)
{
    if (!strcmp (computed, correct))
        printf ("sha-%d %ld(%d) okay\n", alg, rpt, strlen (inp));
    else    printf ("sha-%d verification failure:  %ld repeats of \"%s\"\n"
            "%s: computed\n"
            "%s: expected value\n\n"
            , alg, rpt, inp, computed, correct);
}

static void
chk (int hsize, const char *s, long rpt, const char *correct_value)
{
    SHA2CB  *cb = sha2_init (hsize);
    long    n = strlen (s);
    for (long j = 0;  j < rpt;  ++j)
        sha2_upd (cb, (_u8 *) s, n);
    sha2_end (cb);
    char    outbuf [SHA2_512_FMT_LEN];
    sha2_fmt (cb, outbuf, 16);
    verify (outbuf, correct_value, rpt, s, cb -> hash_size);
    sha2_close (cb);
}



int
main (int argc, char **argv)
{
    int j, n;
    FILE    *f;
static  _u8 buf [1024*20];

    if (argc == 1)
    {
        printf ("validating functionality with published examples\n");
        chk (160, "abc", 1, "a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d");
        chk (160, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
            1, "84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1");
        chk (160, "a", 1000000L,
            "34aa973c d4c4daa4 f61eeb2b dbad2731 6534016f");

        chk (256, "abc", 1, "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad");
        chk (256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
            1, "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1");
        chk (256, "a", 1000000L,
            "cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0");

        chk (384, "abc", 1,
            "cb00753f45a35e8b b5a03d699ac65007 272c32ab0eded163 "
            "1a8b605a43ff5bed 8086072ba1e7cc23 58baeca134c825a7");
        chk (384, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
            1,
            "09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 "
            "2fa08086e3b0f712 fcc7c71a557e2db9 66c3e9fa91746039");
        chk (384, "a", 1000000L,
            "9d0e1809716474cb 086e834e310a4a1c ed149e9c00f24852 "
            "7972cec5704c2a5b 07b8b3dc38ecc4eb ae97ddd87f3d8985");

        chk (512, "abc", 1,
            "ddaf35a193617aba cc417349ae204131 12e6fa4e89a97ea2 0a9eeee64b55d39a "
            "2192992a274fc1a8 36ba3c23a3feebbd 454d4423643ce80e 2a9ac94fa54ca49f");
        chk (512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
            1,
            "8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 "
            "501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909");
        chk (512, "a", 1000000L,
            "e718483d0ce76964 4e2e42c7bc15b463 8e1f98b13b204428 5632a803afa973eb "
            "de0ff244877ea60a 4cb0432ce577c31b eb009c5c2c49aa2e 4eadb217ad8cc09b");
        return 0;
    }

    if (argc == 2 && !strcmp (argv [1], "rot_r"))
    {
        int64   v (1);

        for (int j = 0;  j < 68;  ++j)
        {
            int64 y = v.rot_r (j);
            printf ("%d: %s\n", j, y.to_x ((char *)buf));
        }
        return 0;
    }

    int opt_160 = 0, opt_256 = 0, opt_384 = 0, opt_512 = 0;
    int opt_bufsize = sizeof buf;

    for (j = 1;  j < argc;  ++j)
    {
        HS_TIMER    t0;
        int     def = 0;

        if (argv [j][0] == '-')
        {
            switch (argv [j][1])
            {
            case '1':   ++opt_160;  break;
            case '2':   ++opt_256;  break;
            case '3':   ++opt_384;  break;
            case '5':   ++opt_512;  break;
            case 'b':
                long v = strtol (&argv [j][2], NULL, 0);
                if (v <= 0  ||  v > sizeof buf)
                    fprintf (stderr, "invalid buffer size--ignored\n");
                else    opt_bufsize = (int) v;
                break;
            }
            continue;
        }

        // sure would be nice to do wildcard processing here
        f = fopen (argv [j], "rb");
        if (!f)
        {
            fprintf (stderr, "error opening '%s'", argv [j]);
            perror (" for read");
            continue;
        }

        HS_timer_reset (&t0);
        SHA2CB  *c160, *c256, *c384, *c512;

        if (opt_160 + opt_256 + opt_384 + opt_512 == 0)
            def = 1, opt_256 = 1;
        if (opt_160)    c160 = sha2_init (160);
        if (opt_256)    c256 = sha2_init (256);
        if (opt_384)    c384 = sha2_init (384);
        if (opt_512)    c512 = sha2_init (512);

        while (!feof (f))
        {
//          char    txt [150];
            n = fread (buf, 1, opt_bufsize, f);
            if (n < 0)  break;
            if (opt_160)    sha2_upd (c160, buf, n);
            if (opt_256)    sha2_upd (c256, buf, n);
            if (opt_384)    sha2_upd (c384, buf, n);
            if (opt_512)    sha2_upd (c512, buf, n);
//printf ("processed %u bytes, total hashed so far %lu\n", n, c256->len.lo);
//printf ("%s\n",  sha2_fmt (c256, txt));
        }

        if (opt_160)    sha2_end (c160);
        if (opt_256)    sha2_end (c256);
        if (opt_384)    sha2_end (c384);
        if (opt_512)    sha2_end (c512);

        printf ("* * * File %s (%lu bytes): %.2f seconds\n",
            argv [j], ftell (f), HS_timer_elapsed (&t0) / 100.0);
        fclose (f);

        char    outbuf1 [SHA2_160_FMT_LEN];
        char    outbuf2 [SHA2_256_FMT_LEN];
        char    outbuf3 [SHA2_384_FMT_LEN];
        char    outbuf4 [SHA2_512_FMT_LEN];
        if (opt_160)    printf ("sha160: %s\n\n",  sha2_fmt (c160, outbuf1));
        if (opt_256)    printf ("sha256: %s\n\n",  sha2_fmt (c256, outbuf2));
        if (opt_384)    printf ("sha384:\n%s\n\n", sha2_fmt (c384, outbuf3, 4));
        if (opt_512)    printf ("sha512:\n%s\n\n", sha2_fmt (c512, outbuf4, 4));
        printf ("\n");
        if (opt_160)    sha2_close (c160);
        if (opt_256)    sha2_close (c256);
        if (opt_384)    sha2_close (c384);
        if (opt_512)    sha2_close (c512);
        if (def)
            opt_256 = 0;
    }
    return 0;
}
#endif /* DBG_SHA2_LIB */

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM