【數獨個人專案】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"},
-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:
之後嘗試了安裝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());
}
}
};
}