【数独个人项目】ConsolePatameter类的单元测试

5. 测试阶段

ConsolePatameter类的单元测试

      用的vs自带的单元测试,在解决方案资源管理器里新建“本机单元测试“项目,将测试代码写入,(不是自动测试)需要手写测试测试代码和用例进去。。

1. 写测试代码和用例:2小时

测试用例设计:

    黑盒测试,(白盒的话分支太多了。。不过尽管是黑盒,设计用例的时候也考虑到了程序中的分支,想尽可能覆盖所有的分支)。要测试的有:

①. 常规合法输入用例

(顺序为:argc,argv数组,GetCommand()返回值、GetOperationcode_c()返回值、GetOperationcode_s()返回值)

         {3, {"exename", "-c", "100"}, 'c', 100, "\0"},
         {3, {"exename", "-s", "mypath"}, 's', -1, "mypath"},

②. 边界条件

        {3, {"exename", "-c", "-1"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "0"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "1"}, 'c', 1, "\0"},
        {3, {"exename", "-c", "2"}, 'c', 2, "\0"},
        {3, {"exename", "-c", "999999"}, 'c', 999999, "\0"},
        {3, {"exename", "-c", "1000000"}, 'c', 1000000, "\0"},
        {3, {"exename", "-c", "1000001"}, '\0', -1, "\0"},

③. 其他的,尽可能能覆盖所有分支的所有用例

argc不为3的:

        {1, {"exename" }, '\0', -1, "\0"},
        {2, {"exename", "-c"}, '\0', -1, "\0"},
        {2, {"exename", "aaaaaaaaaaaaaaaaa"}, '\0', -1, "\0"},
        {4, {"exename", "-ccc", "12345", "12345"}, '\0', -1, "\0"},

扫描二维码关注公众号,回复: 4716620 查看本文章

-c且后面参数不合法的

        {3, {"exename", "-c", "ccccc"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "123a"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "&&&&"}, '\0', -1, "\0"},

-s且后面参数不合法的
        {3, {"exename", "-s", "&&my&&path"}, 's', -1, "&&my&&path"},
        {3, {"exename", "-s", "12345"}, 's', -1, "12345"},

根本就不是-c或者-s的
        {3, {"exename", "123", "12345"}, '\0', -1, "\0"},
        {3, {"exename", "-ccc", "12345"}, '\0', -1, "\0"},
        {3, {"exename", "-sss", "12345"}, '\0', -1, "\0"},
        {4, {"exename", "-ccc", "12345", "12345"}, '\0', -1, "\0"},

2. 问题和解决方法:

1. 一开始模块和控制台输入有关系,没法单元测试。。必须得是独立的模块才能测试,于是把模块加了个接口,把这个模块和控制台分开了,类的输入参数多了argc和argv,而不是直接调用控制台的argc和argv

2. 还有个问题就是要不要测试private成员变量,(因为有个void的初始化函数,改变了private成员变量,如果要测试的话,需要加个#define private public)。后来想了下应该不用,因为当时测试的是ConsoleParameter这个类。只要类提供的公有方法的输入输出符合预期就够了,不用管内部实现。当然更细的测试的话就会有这个问题了,比如测试类中的特定一个函数(void Init()函数)

3. 更改测试错误:1小时

测试出错,只有错误信息,没找到测试程序的控制台输出在哪??难道只能调试看值么?

这样的话甚至哪个用例出错都看不出来的啊。。应该分成多个用例么?那每个用例复制一遍测试代码?那样太麻烦了吧。。我看一个测试用例只能输出一个通过/不通过(比如我的这20个用例,输出的就是一个通过)

不过后来把错误弄好了,是测试程序内部的错误,指针的问题,不是模块的错误

4. 测试通过

 

5. 测试代码分支覆盖率

因为用visual studio 17 企业版好像有bug,网上的解决方法很少,试过了也没法解决这个bug:

https://social.microsoft.com/Forums/zh-CN/f794a986-3511-44f6-b696-c93338175a93/vs2017-202251999429256c-3903330446-21333208032797935797?forum=vstudiozhchs

之后尝试了安装OpenCppCoverage插件,也没安装成功。。也出错了。。

// 2018-12-30,用大佬的vs里的OpenCppCoverage插件,测了下分支覆盖率,结果证明。。和下面设想的基本一致

// 详情见 https://blog.csdn.net/qq_37571192/article/details/85412919,集成测试代码分支覆盖率分析

所以只能手工分析下代码分支覆盖率。。

①. 常规合法输入用例

②. 边界条件

③. 尽可能能覆盖所有分支的所有用例

1. argc不为3的:

2.  argc为3:

-c且后面参数不合法的 / 合法的

-s且后面参数不合法的 / 合法的

根本就不是-c或者-s的

 

其中③的测试用例就是根据代码的选择分支条件来设计的,选择的分支覆盖率已经达到了100%,已经覆盖全部分支

所以可以确保测试用例的覆盖的全面性,能覆盖所有分支,所以能覆盖基本上所有代码

附:测试代码:

#include "stdafx.h"
#include "CppUnitTest.h"
#include <iostream>
#include "C:\Users\cky\source\repos\Project6\Project6\ConsoleParameter.h"

#define CASE_AMOUNT 21

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTestForConsolePatameter {
  TEST_CLASS(UnitTest1)
  {
  public:

    TEST_METHOD(Class_ConsoleParameter)
    {
      struct Testcase {
        int argc;
        char consoleinput[105][105];
        char expect_output_command;
        int expect_output_operationcode_c;
        string expect_output_operationcode_s;
      };
      struct Testcase testcase[CASE_AMOUNT] = {
        {1, {"exename" }, '\0', -1, "\0"},
        {2, {"exename", "-c"}, '\0', -1, "\0"},
        {2, {"exename", "aaaaaaaaaaaaaaaaa"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "100"}, 'c', 100, "\0"},
        {3, {"exename", "-s", "mypath"}, 's', -1, "mypath"},

        {3, {"exename", "-c", "-1"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "0"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "1"}, 'c', 1, "\0"},
        {3, {"exename", "-c", "2"}, 'c', 2, "\0"},
        {3, {"exename", "-c", "999999"}, 'c', 999999, "\0"},
        {3, {"exename", "-c", "1000000"}, 'c', 1000000, "\0"},
        {3, {"exename", "-c", "1000001"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "ccccc"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "123a"}, '\0', -1, "\0"},
        {3, {"exename", "-c", "&&&&"}, '\0', -1, "\0"},
        {3, {"exename", "-s", "&&my&&path"}, 's', -1, "&&my&&path"},
        {3, {"exename", "-s", "12345"}, 's', -1, "12345"},

        {3, {"exename", "123", "12345"}, '\0', -1, "\0"},
        {3, {"exename", "-ccc", "12345"}, '\0', -1, "\0"},
        {3, {"exename", "-sss", "12345"}, '\0', -1, "\0"},
        {4, {"exename", "-ccc", "12345", "12345"}, '\0', -1, "\0"},
      };
      for (int i = 0; i < CASE_AMOUNT; i++) {
        char *ptr[105] = { NULL };
        
        for (int j = 0; j < testcase[i].argc; j++) {
          ptr[j] = testcase[i].consoleinput[j];
        }
        char **argv = ptr;

        ConsoleParameter parameter;
        parameter.Init(testcase[i].argc, argv);

        Assert::AreEqual(testcase[i].expect_output_command, parameter.GetCommand());
        Assert::AreEqual(testcase[i].expect_output_operationcode_c, parameter.GetOperationcode_c());
        Assert::AreEqual(testcase[i].expect_output_operationcode_s, parameter.GetOperationcode_s());
      }
    }
  };
}

 

猜你喜欢

转载自blog.csdn.net/qq_37571192/article/details/85265564
今日推荐