• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

软件测试之CppUnit - 测试驱动开发入门

发布: 2009-3-30 10:03 | 作者: 不详 | 来源: 测试时代采编 | 查看: 230次 | 进入软件测试论坛讨论

领测软件测试网

 {
        FileStatus status( mFileNameExist );
        CPPUNIT_ASSERT_EQUAL( status.getFileName(), mFileNameExist );
    }
    void testGetFileSize()
    {
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT_EQUAL( exist.getFileSize(), (DWORD)FILE_SIZE );
        FileStatus notExist( mFileNameNotExist );
        CPPUNIT_ASSERT_THROW( notExist.getFileSize(), FileStatusError );
    }
    void testFileExist()
    {
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT( exist.fileExist() );
        FileStatus notExist( mFileNameNotExist );
        CPPUNIT_ASSERT( ! notExist.fileExist() );
    }
    void testFileModifyDateBasic()
    {
        FILETIME fileTime;
        GetSystemTimeAsFileTime( &fileTime );
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT_NO_THROW( exist.getFileModifyDate() );
        CPPUNIT_ASSERT_NO_THROW( exist.setFileModifyDate( &fileTime ) );
        FileStatus notExist( mFileNameNotExist );
        CPPUNIT_ASSERT_THROW( exist.getFileModifyDate(), FileStatusError );
        CPPUNIT_ASSERT_THROW( exist.setFileModifyDate( &fileTime ), FileStatusError );
    }
    void testFileModifyDateEqual()
    {
        FILETIME fileTime;
        GetSystemTimeAsFileTime( &fileTime );
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT_NO_THROW( exist.setFileModifyDate( &fileTime ) );
        FILETIME get = exist.getFileModifyDate();
        CPPUNIT_ASSERT( CompareFileTime( &get, &fileTime ) == 0 );
    }
};

int main()
{
    CPPUNIT_NS::TestResult r;
    CPPUNIT_NS::TestResultCollector result;
    r.addListener( &result );
    CPPUNIT_NS::TestCallertestCase1( "testCtorAndGetName", MyTestCase::testCtorAndGetName );
    CPPUNIT_NS::TestCallertestCase2( "testGetFileSize", MyTestCase::testGetFileSize );
    CPPUNIT_NS::TestCallertestCase3( "testFileExist", MyTestCase::testFileExist );
    CPPUNIT_NS::TestCallertestCase4( "testFileModifyDateBasic", MyTestCase::testFileModifyDateBasic );
    CPPUNIT_NS::TestCallertestCase5( "testFileModifyDateEqual", MyTestCase::testFileModifyDateEqual );
    testCase1.run( &r );
    testCase2.run( &r );
    testCase3.run( &r );
    testCase4.run( &r );
    testCase5.run( &r );
    CPPUNIT_NS::TextOutputter out( &result, std::cout );
    out.write();
    return 0;
}

运行测试,发现两个错误:

1) test: testFileModifyDateBasic (F) line: 140 c:unittestunittest.cpp
assertion failed
- Unexpected exception caught


2) test: testFileModifyDateEqual (F) line: 150 c:unittestunittest.cpp
assertion failed
- Unexpected exception caught

调试发现,原来我的setFileModifyDate中,文件的打开方式为GENERIC_READ,只有读权限,自然不能写。把这个替换为 GENERIC_READ | GENERIC_WRITE,再运行,一切OK!
其实上面的测试以及实现代码还有一些问题,譬如说,测试用例分得还不够细,有些测试可以继续细分为几个函数,这样一旦遇到测试错误,你可以很精确的知道错误的位置(因为抛出异常错误是不能知道行数的)。不过用来说明怎样进行测试驱动开发应该是足够了。

VI. 测试集

CPPUNIT_NS::TestCallertestCase1( "testCtorAndGetName", MyTestCase::testCtorAndGetName );
CPPUNIT_NS::TestCallertestCase2( "testGetFileSize", MyTestCase::testGetFileSize );
CPPUNIT_NS::TestCallertestCase3( "testFileExist", MyTestCase::testFileExist );
CPPUNIT_NS::TestCallertestCase4( "testFileModifyDateBasic", MyTestCase::testFileModifyDateBasic );
CPPUNIT_NS::TestCallertestCase5( "testFileModifyDateEqual", MyTestCase::testFileModifyDateEqual );

这段代码虽然还不够触目惊心,但是让程序员来做这个,的确是太浪费了。CppUnit为我们提供了一些机制来避免这样的浪费。我们可以修改我们的测试代码为:

class MyTestCase:public CPPUNIT_NS::TestFixture
{
    std::string mFileNameExist;
    std::string mFileNameNotExist;
    std::string mTestFolder;
    enum DUMMY
    {
        FILE_SIZE = 1011
    };
    CPPUNIT_TEST_SUITE( MyTestCase );
        CPPUNIT_TEST( testCtorAndGetName );
        CPPUNIT_TEST( testGetFileSize );
        CPPUNIT_TEST( testFileExist );
        CPPUNIT_TEST( testFileModifyDateBasic );
        CPPUNIT_TEST( testFileModifyDateEqual );
    CPPUNIT_TEST_SUITE_END();
public:
    virtual void setUp()
    {
        mTestFolder = "c:justfortest";
        mFileNameExist = mTestFolder + "exist.dat";
        mFileNameNotExist = mTestFolder + "notexist.dat";
        if( GetFileAttributes( mTestFolder.c_str() ) != INVALID_FILE_ATTRIBUTES )
            throw std::exception( "test folder already exists" );
        if( ! CreateDirectory( mTestFolder.c_str() ,NULL ) )
            throw std::exception( "cannot create folder" );
        HANDLE file = CreateFile( mFileNameExist.c_str(), GENERIC_READ | GENERIC_WRITE,
            0, NULL, CREATE_NEW, 0, NULL );
        if( file == INVALID_HANDLE_VALUE )
            throw std::exception( "cannot create file" );
        char buffer[FILE_SIZE];
        DWORD bytesWritten;
        if( !WriteFile( file, buffer, FILE_SIZE, &bytesWritten, NULL ) ||
            bytesWritten != FILE_SIZE )
        {
            CloseHandle( file );
            throw std::exception( "cannot write file" );
        }
        CloseHandle( file );
    }
    virtual void tearDown()
    {
        if( ! DeleteFile( mFileNameExist.c_str() ) )
            throw std::exception( "cannot delete file" );
        if( ! RemoveDirectory( mTestFolder.c_str() ) )
            throw std::exception( "cannot remove folder" );
    }
    void testCtorAndGetName()
    {
        FileStatus status( mFileNameExist );
        CPPUNIT_ASSERT_EQUAL( status.getFileName(), mFileNameExist );
    }
    void testGetFileSize()
    {
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT_EQUAL( exist.getFileSize(), (DWORD)FILE_SIZE );
        FileStatus notExist( mFileNameNotExist );
        CPPUNIT_ASSERT_THROW( notExist.getFileSize(), FileStatusError );
    }
    void testFileExist()
    {
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT( exist.fileExist() );
        FileStatus notExist( mFileNameNotExist );
        CPPUNIT_ASSERT( ! notExist.fileExist() );
    }
    void testFileModifyDateBasic()
    {
        FILETIME fileTime;
        GetSystemTimeAsFileTime( &fileTime );
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT_NO_THROW( exist.getFileModifyDate() );
        CPPUNIT_ASSERT_NO_THROW( exist.setFileModifyDate( &fileTime ) );
        FileStatus notExist( mFileNameNotExist );
        CPPUNIT_ASSERT_THROW( notExist.getFileModifyDate(), FileStatusError );
        CPPUNIT_ASSERT_THROW( notExist.setFileModifyDate( &fileTime ), FileStatusError );
    }
    void testFileModifyDateEqual()
    {
        FILETIME fileTime;
        GetSystemTimeAsFileTime( &fileTime );
        FileStatus exist( mFileNameExist );
        CPPUNIT_ASSERT_NO_THROW( exist.setFileModifyDate( &fileTime ) );
        FILETIME get = exist.getFileModifyDate();
        CPPUNIT_ASSERT( CompareFileTime( &get, &fileTime ) == 0 );
    }
};

CPPUNIT_TEST_SUITE_REGISTRATION( MyTestCase );

int main()
{
    CPPUNIT_NS::TestResult r;
    CPPUNIT_NS::TestResultCollector result;
    r.addListener( &result );
    CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest()->run( &r );
    CPPUNIT_NS::TextOutputter out( &result, std::cout );
    out.write();
    return 0;
}

这里的

    CPPUNIT_TEST_SUITE( MyTestCase );
        CPPUNIT_TEST( testCtorAndGetName );
        CPPUNIT_TEST( testGetFileSize );
        CPPUNIT_TEST( testFileExist );
        CPPUNIT_TEST( testFileModifyDateBasic );
        CPPUNIT_TEST( testFileModifyDateEqual );
    CPPUNIT_TEST_SUITE_END();

最重要的内容其实是定义了一个函数suite,这个函数返回了一个包含了所有CPPUNIT_TEST定义的测试用例的一个测试集。CPPUNIT_TEST_SUITE_REGISTRATION通过静态注册把这个测试集注册到全局的测试树中,最后通过CPPUNIT_NS::TestFactoryRegistry::getRegistry(). makeTest()生成一个包含所有测试用例的测试并且运行。具体的内部运行机制请参考CppUnit代码简介。

VII. 小节

这篇文章简要的介绍了CppUnit和测试驱动开发的基本概念,虽然CppUnit还有很多别的功能,譬如说基于GUI的测试环境以及和编译器Post Build相连接的测试输出,以及对于测试系统的扩展等,但是基本上掌握了本文中的内容就可以进行测试驱动的开发了。

此外,测试驱动开发还可以检验需求的错误。其实我选用GetFileTime和 SetFileTime作为例子是因为,有些系统上,SetFileTime所设置的时间是有一定的精度的,譬如说按秒,按天,...,因此你设置了一个时间后,可能get回来的时间和它不同。这其实是一个需求的错误。当然由于我的系统上没有这个问题,所以我也就不无病呻吟了。具体可以参考MSDN中对于这两个函数的介绍。

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/


关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备10010545号-5
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网