博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
软件工程第2次作业——Visual Studio 2017下基于C/C++的VSTS单元测试实践
阅读量:5037 次
发布时间:2019-06-12

本文共 8136 字,大约阅读时间需要 27 分钟。

Write one minute, test all day long.

环境确定

IDE:Microsoft Visual Studio 2017 Community

语言:C++
单元测试工具:VSTS

IDE

此处使用Visual Studio 2017 Community作为开发环境,安装Visual Studio 2017如图:

1648849-20190411211203683-1226816261.png

语言

这里使用C++作为程序语言,因为我最开始接触的是C++

单元测试工具

C++语言项目的单元测试是通过VSTS在Windows对于C++的托管平台C++/CLI上完成的,通过创建C++的单元测试项目即可对C++的程序项目进行单元测试。

测试案例

本测试用例旨在实现一个二维向量类Vector2并实现其一些简单的运算操作,关于类自身的组成如下

1648849-20190411211721395-252259270.png

除了类本身以外还存在一些运算功能,将在代码中列出。

案例实现

这里将给出测试用例的具体定义和实现,在Visual Studio 2017中新建一个Visual C++的项目选择空项目,并创建项目,由于该项目只是一个功能模块,因此在项目属性中设置该项目为“静态库(.lib)”

1648849-20190411213346077-848315863.png
然后新建文件Vec.h和Vec.cpp进行功能的实际编码:

接口

///File : Vec.h#pragma onceclass Vector2{public:    union    {        float comp[2];        struct        {            float x;            float y;        };    };                      //向量的分量    Vector2();    Vector2(float, float);    float Length();         //模长    float DirRad();         //方向角    Vector2 Unit();         //此向量对应单位向量    void Normalize();       //对该向量单位化(破坏性)    bool IsNormalized();    //判断向量是否是单位向量    bool IsZero();          //判断向量是否是零向量    bool IsValid();         //判断向量是否有效(不含有NAN和无穷)};extern Vector2 operator+(Vector2 v0, Vector2 v1);   // 向量加法extern Vector2 operator-(Vector2 v0, Vector2 v1);   // 向量减法extern Vector2 operator*(float s, Vector2 v);       // 向量数乘extern Vector2 operator*(Vector2 v, float s);       // 向量数乘(交换律)extern Vector2 operator/(Vector2 v, float s);       // 向量数除(倒数相乘)extern bool operator==(Vector2 v0, Vector2 v1);     // 向量判等extern bool operator!=(Vector2 v0, Vector2 v1);     // 向量不等extern float DotProd(Vector2 v0, Vector2 v1);       // 数量积extern float operator^(Vector2 v0, Vector2 v1);     // 夹角

实现

注意:

这里的实现实际上有问题,其问题将在测试时被暴露出来

///File : Vec.cpp#include "Vec.h"#include 
using namespace std;Vector2::Vector2() : x(0), y(0){}Vector2::Vector2(float xf, float yf) : x(xf), y(yf){}float Vector2::Length(){ return sqrt(x*x+y*y);}float Vector2::DirRad(){ if (IsZero()||!IsValid()) { return NAN; } return atan2(y, x);}Vector2 Vector2::Unit(){ return *this / Length();}void Vector2::Normalize(){ Vector2 vUnit = this->Unit(); *this = vUnit;}bool Vector2::IsNormalized(){ return abs(Length()-1.0f) < 1e-6;}bool Vector2::IsZero(){ return abs(x) < 1e-6 && abs(y) < 1e-6;}bool Vector2::IsValid(){ return (isnan(x) || isnan(y) || isinf(x) || isinf(y));}Vector2 operator+(Vector2 v0, Vector2 v1){ return Vector2(v0.x + v1.x, v0.y + v1.y);}Vector2 operator-(Vector2 v0, Vector2 v1){ return Vector2(v0.x - v1.x, v0.y - v1.y);}Vector2 operator*(float s, Vector2 v){ if (isnan(s) || !v.IsValid()) { return Vector2(NAN, NAN); } return Vector2(v.x*s,v.y*s);}Vector2 operator*(Vector2 v, float s){ return s * v;}Vector2 operator/(Vector2 v, float s){ return Vector2(v.x/s,v.y/s);}bool operator==(Vector2 v0, Vector2 v1){ return abs(v0.x-v1.x) < 1e-6 && abs(v0.y-v1.y) < 1e-6;}bool operator!=(Vector2 v0, Vector2 v1){ return ! (v0 == v1);}float DotProd(Vector2 v0, Vector2 v1){ return v0.x*v1.x + v0.y*v1.y;}float operator^(Vector2 v0, Vector2 v1){ float dp = DotProd(v0, v1); if (!isnan(dp)) { dp = dp / (v0.Length()*v1.Length()); } return dp;}

单元测试代码与测试用例

单元测试本应当考虑覆盖所有测试内容,但这里由于被测试的功能非常多,并对应多种可能情况,这里只为了说明代码测试的功能,本次测试用例仅满足函数覆盖(但实际上至少应达到语句覆盖)

原有项目所在的解决方案下新建一个本机单元测试项目,并在引用中加入原有项目。
1648849-20190411213922597-1145307049.png
1648849-20190411214028976-1452420959.png

然后对原有项目进行一次生成,并将该lib文件输入到测试项目的链接器中:

1648849-20190411214153569-782108557.png

并编写如下的测试代码(该测试仅满足函数覆盖):

///File : unittest1.cpp#include "stdafx.h"#include "CppUnitTest.h"#include "..\Assignments02\Vec.h"using namespace Microsoft::VisualStudio::CppUnitTestFramework;namespace UnitTestA02{           TEST_CLASS(UnitTest1)    {    public:                TEST_METHOD(TestConstruct)        {            Vector2 v0;            Vector2 v1(3, 4);            Assert::AreEqual(v0.x, 0.0f, FLT_EPSILON);            Assert::AreEqual(v1.x, 3.0f, FLT_EPSILON);            Assert::AreEqual(v1.y, 4.0f, FLT_EPSILON);        }        TEST_METHOD(TestMemberFunc)        {            Vector2 v;            float realdir = NAN;            Assert::IsTrue(v.IsZero());            Assert::IsTrue(isnan(v.DirRad()));            Assert::AreEqual(v.Length(), 0.0f, FLT_EPSILON);            Assert::IsFalse(v.Unit().IsValid());            v = { 3,4 };            realdir = atan2(4, 3);            Assert::IsFalse(v.IsZero());            Assert::AreEqual(v.Length(), 5.0f, FLT_EPSILON);            Assert::IsTrue(v.IsValid());            Assert::AreEqual(v.DirRad(), atan2f(4,3), FLT_EPSILON);            Assert::AreEqual(v.Unit().x, 3.0f / 3.0f*cosf(atan2f(4, 3)), FLT_EPSILON);            Assert::AreEqual(v.Unit().y, 4.0f / 4.0f*sinf(atan2f(4, 3)), FLT_EPSILON);            Assert::IsFalse(v.IsNormalized());            v.Normalize();            Assert::IsTrue(v.IsValid());            Assert::AreEqual(v.DirRad(), realdir, FLT_EPSILON);            Assert::IsTrue(v.IsNormalized());            Assert::AreEqual(v.x, v.Unit().x, FLT_EPSILON);            Assert::AreEqual(v.y, v.Unit().y, FLT_EPSILON);        }        TEST_METHOD(TestOperation)        {            Vector2 v0(2.0f, 4.0f);            Vector2 v1(-5.0f, 7.0f);            Vector2 vres;            float fres = 0.0f;            vres = v0 + v1;            Assert::AreEqual(vres.x, v0.x + v1.x, FLT_EPSILON);            Assert::AreEqual(vres.y, v0.y + v1.y, FLT_EPSILON);            vres = v0 - v1;            Assert::AreEqual(vres.x, v0.x - v1.x, FLT_EPSILON);            Assert::AreEqual(vres.y, v0.y - v1.y, FLT_EPSILON);            vres = v0 * 2;            Assert::AreEqual(vres.x, 4.0f, FLT_EPSILON);            Assert::AreEqual(vres.y, 8.0f, FLT_EPSILON);            vres = v0 / 2;            Assert::AreEqual(vres.x, 1.0f, FLT_EPSILON);            Assert::AreEqual(vres.y, 2.0f, FLT_EPSILON);            fres = DotProd(v0, v1);            Assert::AreEqual(fres, 18.0f, FLT_EPSILON);            fres = v0 ^ v1;        }    };}

之后运行测试,发现存在测试错误:

1648849-20190411214509489-352426964.png

将存在的测试错误完整信息复制,得到:

测试名称:   TestOperation测试全名:   UnitTestA02::UnitTest1::TestOperation测试源:    p:\visual studio 2017 projects\softwareengineeringassignments\unittesta02\unittest1.cpp : 第 47 行测试结果:   失败测试持续时间: 0:00:00.0101092结果 StackTrace:  at UnitTestA02::UnitTest1::TestOperation() in p:\visual studio 2017 projects\softwareengineeringassignments\unittesta02\unittest1.cpp组名称: UnitTestA02分组依据: Hierarchy组全名: UnitTestA02持续时间: 0:00:00.49471012 个测试失败0 个测试跳过1 个测试通过结果1 名称: TestMemberFunc结果1 结果: 失败结果1 持续时间:   0:00:00.4836651结果1 StackTrace: at UnitTestA02::UnitTest1::TestMemberFunc() in p:\visual studio 2017 projects\softwareengineeringassignments\unittesta02\unittest1.cpp:line 29结果1 消息: Assert failed结果1 StandardOutput:结果1 StandardError:结果2 名称: TestOperation结果2 结果: 失败结果2 持续时间:   0:00:00.0103944结果2 StackTrace: at UnitTestA02::UnitTest1::TestOperation() in p:\visual studio 2017 projects\softwareengineeringassignments\unittesta02\unittest1.cpp:line 60结果2 消息: Assert failed. Expected:<-nan(ind)> Actual:<4>结果2 StandardOutput:结果2 StandardError:结果3 名称: TestConstruct结果3 结果: 已通过结果3 持续时间:   0:00:00.0006506结果3 StackTrace:结果3 消息:结果3 StandardOutput:结果3 StandardError:结果 消息:  Assert failed. Expected:<2> Actual:<4>

由于在测试时没有将各个断言分立进行,而是分成三个模块将断言分组进行,因此每个分组只能同期得到一个错误结果(即不会得到所有的错误结果,而是每一个测试程序内第一个失败的断言处),这尽管减少了测试用例的代码量,但降低了测试修改然后回归测试的效率(因为无法一次性定位所有错误),因此在实际测试中,可考虑尽量保证各个断言分立进行(这有助于定位错误,但相对应的,测试代码量和测试时间会变)。

经过排查后发现,是成员函数IsValid内部的错误:

//原来的bool Vector2::IsValid(){    return (isnan(x) || isnan(y) || isinf(x) || isinf(y));}//正确的bool Vector2::IsValid(){    return !(isnan(x) || isnan(y) || isinf(x) || isinf(y));}

将错误修改之后再次进行用例测试,结果正确:

1648849-20190411214834619-1858445155.png

组名称: UnitTestA02分组依据: Hierarchy组全名: UnitTestA02持续时间: 0:00:00.00158270 个测试失败0 个测试跳过3 个测试通过结果1 名称: TestConstruct结果1 结果: 已通过结果1 持续时间:   0:00:00.0007287结果1 StackTrace:结果1 消息:结果1 StandardOutput:结果1 StandardError:结果2 名称: TestMemberFunc结果2 结果: 已通过结果2 持续时间:   0:00:00.0004756结果2 StackTrace:结果2 消息:结果2 StandardOutput:结果2 StandardError:结果3 名称: TestOperation结果3 结果: 已通过结果3 持续时间:   0:00:00.0003784结果3 StackTrace:结果3 消息:结果3 StandardOutput:结果3 StandardError:

测试告一段落。

测试说明

这些测试用例尽管没能达到语句覆盖,但测试了各个功能能否正常工作,以及是否得到了预期的结果,并且对一部分极端的情况进行了考察,最终,测试通过。

由于Visual Studio 2017 Community中不支持代码覆盖率分析功能,因此这里无法提供关于代码覆盖率更加详细的相关信息。

Visual Studio的代码覆盖率分析功能是Enterprise版特有的。
此时,微软露出了和某Gabe一样令人胆寒的微笑

转载于:https://www.cnblogs.com/oberon-zjt0806/p/10692710.html

你可能感兴趣的文章
graphite custom functions
查看>>
ssh无密码登陆屌丝指南
查看>>
一个自己写的判断2个相同对象的属性值差异的工具类
查看>>
[CF803C] Maximal GCD(gcd,贪心,构造)
查看>>
oracle连接的三个配置文件(转)
查看>>
Java 8 中如何优雅的处理集合
查看>>
[HNOI2012]永无乡 线段树合并
查看>>
Centos下源码安装git
查看>>
gulp-rev-append md5版本号
查看>>
IO流之File类
查看>>
sql 基础语句
查看>>
CF717A Festival Organization(第一类斯特林数,斐波那契数列)
查看>>
控件发布:div2dropdownlist(div模拟dropdownlist控件)
查看>>
Oracle composite index column ordering
查看>>
kaggle竞赛
查看>>
区块链入门教程
查看>>
npm常用命令
查看>>
南海区行政审批管理系统接口规范v0.3(规划)4.2.【queryExpireList】当天到期业务查询...
查看>>
[置顶] 细说Cookies
查看>>
[wp7软件]wp7~~新闻资讯,阅读软件下载大全! 集合贴~~~
查看>>