小试QtTest
发布者:
Bean
在我们的代码里面,多处用到std::map<std::string, double>这样的类型。然而问题在于我们的GUI 往往需要将double的值显示出来,这里便涉及一个问题,需要显示多少位小数呢?事实上我们牵涉的情况多数属于nm的数值,因此三位小数是完全足矣!如果计及um的情况,三位是必需的。不过,从我们的代码,却看不出应该保留多少位。
最近有个ticket,是要求在condition setup时,只需保留3位小数。因此我大胆的写了一个类Milliuno,其作用之一是替代double,但只保留三位小数,其二是提供字符串格式接口,以保 证表示的一致。该类如下:
// milliuno.h
#ifndef _MILLIUNO_H_
#define _MILLIUNO_H_
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <map>
#include <cmath>
class Milliuno
{
public:
Milliuno ( double m = 0.0 ) {
m_d = static_cast<int>( m * 1E3 ) * 1E-3;
}
Milliuno (int m) : m_d ( m ) {}
Milliuno ( const char* m ) {
std::stringstream ss;
ss << m;
ss >> m_d;
m_d = static_cast<int>( m_d * 1E3 ) * 1E-3;
}
Milliuno ( const std::string& m ) {
std::stringstream ss;
ss << m;
ss >> m_d;
m_d = static_cast<int>( m_d * 1E3 ) * 1E-3;
}
Milliuno ( const Milliuno& m ) : m_d( m.m_d ) {}
operator double() const {
return m_d;
}
operator std::string() const {
std::ostringstream oss;
oss << std::setprecision( 3 ) << std::fixed << m_d;
return oss.str();
}
Milliuno& operator=( const Milliuno& m ) {
if ( this == &m ) {
return *this;
}
m_d = m.m_d;
return *this;
}
Milliuno& operator=( double m ) {
m_d = static_cast<int>( m * 1E3 ) * 1E-3;
return *this;
}
Milliuno& operator=( const std::string& m ) {
std::stringstream ss;
ss << m;
ss >> m_d;
m_d = static_cast<int>( m_d * 1E3 ) * 1E-3;
return *this;
}
Milliuno& operator=( const char* m ) {
std::stringstream ss;
ss << m;
ss >> m_d;
m_d = static_cast<int>( m_d * 1E3 ) * 1E-3;
return *this;
}
Milliuno& operator*=( double m ) {
m_d = static_cast<int>( m_d * m * 1E3 ) * 1E-3;
return *this;
}
bool operator==( const Milliuno& rhs ) {
return fabs( m_d - rhs.m_d ) < 1E-3;
}
bool operator==( const double& rhs ) {
return fabs( m_d - rhs ) < 1E-3;
}
const std::string str() const {
std::ostringstream oss;
oss << std::setprecision( 3 ) << std::fixed << m_d;
return oss.str();
}
double val() const {
return m_d;
}
friend std::ostream& operator<<( std::ostream& os, const Milliuno& m ) {
os << std::string( m );
return os;
}
private:
double m_d;
};
#endif // _MILLIUNO_H_
现在要做的事情是,测试!
这次我不用google的测试框架,试下用Qt的QtTest, 直接上代码:
// milliuno.cpp
#include <QtTest/QtTest>
#include <milliuno.h>
class TestMilliuno: public QObject
{
Q_OBJECT
private slots:
void ctorDefault();
void ctorfromString();
void ctorfromCString();
void ctorfromDouble();
void copyAssignfromString();
void copyAssignfromCString();
void copyAssignfromDouble();
void copyAssignfromMilliuno();
void equalsToDouble();
void equalsToMilliuno();
};
void TestMilliuno::ctorDefault()
{
Milliuno milliuno;
QCOMPARE(milliuno.val(), 0.0);
}
void TestMilliuno::ctorfromDouble()
{
Milliuno milliuno (1.2345);
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::ctorfromString()
{
Milliuno milliuno (std::string("1.2345"));
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::ctorfromCString()
{
Milliuno milliuno ("1.2345");
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::copyAssignfromString()
{
Milliuno milliuno;
milliuno = std::string("1.2345");
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::copyAssignfromCString()
{
Milliuno milliuno;
milliuno = "1.2345";
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::copyAssignfromDouble()
{
Milliuno milliuno;
milliuno = 1.2345;
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::copyAssignfromMilliuno()
{
Milliuno m (1.2345);
Milliuno milliuno = m;
QCOMPARE(milliuno.val(), 1.234);
}
void TestMilliuno::equalsToDouble()
{
Milliuno milliuno (1.2345);
QCOMPARE(milliuno == 1.2349, true);
QCOMPARE(milliuno == 1.236, false);
}
void TestMilliuno::equalsToMilliuno()
{
Milliuno milliuno (1.2345);
Milliuno m (1.2349);
Milliuno n (1.236);
QCOMPARE(milliuno == m, true);
QCOMPARE(milliuno == n, false);
}
QTEST_MAIN(TestMilliuno)
#include "milliuno.moc"
由于使用了Qt,不妨写个qmake project file, 当然用CMake也是可以的。
// milliuno.pro
QT += testlib
SOURCES = milliuno.cpp
直接执行
qmake
make
现在就跑测试了
./milliuno
输出如下
********* Start testing of TestMilliuno *********
Config: Using QTest library 4.8.5, Qt 4.8.5
PASS : TestMilliuno::initTestCase()
PASS : TestMilliuno::ctorDefault()
PASS : TestMilliuno::ctorfromString()
PASS : TestMilliuno::ctorfromCString()
PASS : TestMilliuno::ctorfromDouble()
PASS : TestMilliuno::copyAssignfromString()
PASS : TestMilliuno::copyAssignfromCString()
PASS : TestMilliuno::copyAssignfromDouble()
PASS : TestMilliuno::copyAssignfromMilliuno()
PASS : TestMilliuno::equalsToDouble()
PASS : TestMilliuno::equalsToMilliuno()
PASS : TestMilliuno::cleanupTestCase()
Totals: 12 passed, 0 failed, 0 skipped
********* Finished testing of TestMilliuno *********
在TestMilliuno的每个private slot 函数都是一项测试,对象范围包括构造函数,赋值函数,以及相等比较函数。这里只用到了QtTest的一个功能:QCOMPARE。
QtTest是个强大的框架,提供各种级别的测试。例如基准测试
void TestMilliuno::benchmark()
{
Milliuno m;
Milliuno n;
QBENCHMARK {
m = n.val();
}
}
运行结果如下所示
RESULT : TestMilliuno::benchmark():
0.0000073 msecs per iteration (total: 62, iterations: 8388608)
如果觉得默认的选项没有吸引力,例如迭代次数太少,可以试下./milliuno -help以获取帮助,这里就不细述了。
回顾上面的每个测试函数,里面的测试数据就只有一条,显然没法达到测试的目的。幸好QtTest支持DDT! 数据驱动测试DDT
以ctorfromDouble()为例吧,怎样给这个测试配置用例数据呢?很简单,添加成员函数ctorfromDouble_data()!
void TestMilliuno::ctorfromDouble_data()
{
QTest::addColumn<double>("milliuno");
QTest::addColumn<double>("result");
QTest::newRow("1") << 0.0001 << 0.0;
QTest::newRow("2") << 0.0009 << 0.0;
QTest::newRow("3") << 0.0019 << 0.001;
QTest::newRow("4") << 0.0029 << 0.002;
QTest::newRow("5") << 5.0095 << 5.009;
QTest::newRow("6") << 5.0096 << 5.009;
}
当然,我们需要重写ctorfromDouble()
void TestMilliuno::ctorfromDouble()
{
QFETCH(double, milliuno);
QFETCH(double, result);
QCOMPARE(Milliuno(milliuno).val(), result);
}
容易看出,每条数据是按行存放的,而QTest::addColumn
修改之后,测试的结果相应部分将变为
PASS : TestMilliuno::ctorfromDouble(1)
PASS : TestMilliuno::ctorfromDouble(2)
PASS : TestMilliuno::ctorfromDouble(3)
PASS : TestMilliuno::ctorfromDouble(4)
PASS : TestMilliuno::ctorfromDouble(5)
PASS : TestMilliuno::ctorfromDouble(6)
区别就是多了行标签!在测试结果出错的情况下,其作用不需多说!
睿初科技软件开发技术博客,转载请注明出处
blog comments powered by Disqus
发布日期
标签
最近发表
- volatile与多线程
- TDD practice in UI: Develop and test GUI independently by mockito
- jemalloc源码解析-核心架构
- jemalloc源码解析-内存管理
- boost::bind源码分析
- 小试QtTest
- 一个gtk下的目录权限问题
- Django学习 - Model
- Code snippets from C & C++ Code Capsule
- Using Eclipse Spy in GUI products based on RCP
文章分类
- cpp 3
- wxwidgets 4
- swt/jface 1
- chrome 3
- memory_management 5
- eclipse 1
- 工具 4
- 项目管理 1
- cpplint 1
- 算法 1
- 编程语言 1
- python 5
- compile 1
- c++ 7
- 工具 c++ 1
- 源码分析 c++ 3
- c++ boost 2
- data structure 1
- wxwidgets c++ 1
- template 1
- boost 1
- wxsocket 1
- wxwidget 2
- java 2
- 源码分析 1
- 网路工具 1
- eclipse插件 1
- django 1
- gtk 1
- 测试 1
- 测试 tdd 1
- multithreading 1