Лабораторная работа 4 / UnitTest
.docСанкт-Петербургский Государственный Электротехнический Университет «ЛЭТИ»
Качество и надежность программного обеспечения
Модульное тестирование
(Unit-test)
Выполнили: студенты гр.№2382
Кривенок Д.В.
Мельник И.В.
Шабаев Г.В.
Преподаватель: Щеголева Н.Л.
Санкт-Петербург
2007
В качестве класса для тестирования был выбран класс для нахождения и определения всевозможных URL(ссылок) в тексте – CurlParser. Данный класс предостовляет простую функциональность по находжению ссылки в тексте – он выделяет текст ссылки( строку ) и начальную и конечную позицию данной строки в общем тексте. Входными данными для класса является строка, где возможно находятся сслылки, выходнными данными является массив структур содержащих информацию о строке ссылки и ее позиций в тексте. Данный класс для обработки и анализа строки использует библиотеку boost::spirit.
Для написания теста к данному классу использовалась библиотека boost::test, которая предостовляет широкие возможности по организации тестов в простые “test cases” и “test suites” , а также позволяет контролировать их выполнение.
Данная библиотека состоит из :
-
Test Tools
-
Test Execution Monitor
-
Unit Test Framework
Код класса для тестирования:
#pragma once
#pragma warning (disable : 4512) //Can not generate assignment operator in boost librarie
#pragma warning(disable : 4267)
#include <string.h>
#include <vector>
#include <math.h>
#include <comutil.h>
#include <boost/spirit/core.hpp>
#pragma warning (default : 4512)
#pragma warning(default : 4267)
using namespace boost::spirit;
//using namespace std;
struct CUrlPosition
{
CUrlPosition (DWORD nStart = 0, DWORD nEnd = 0, std::string strUrl = "")
{
m_nStartPos = nStart;
m_nEndPos = nEnd;
m_strUrl = strUrl;
}
DWORD m_nStartPos;
DWORD m_nEndPos;
std::string m_strUrl;
};
typedef std::vector<CUrlPosition> CUrlPostionArr;
typedef std::vector<CUrlPosition> CTextPositionArr;
class PushUrlPos
{
public :
PushUrlPos ( CUrlPostionArr& PosArr
, const char* nCurrentOffset )
: m_PosArr (PosArr)
, m_nCurrentOffset(nCurrentOffset)
{
}
PushUrlPos& operator = (const PushUrlPos& );
void operator ( ) ( const char* lpcszTextStart, const char* lpcszTextEnd) const
{
try
{
CUrlPosition UrlPos;
UrlPos.m_nStartPos = (DWORD) (lpcszTextStart - m_nCurrentOffset); // Length of text in bytes
UrlPos.m_nEndPos = (DWORD) (lpcszTextEnd - m_nCurrentOffset);
UrlPos.m_strUrl.append( lpcszTextStart, 0,UrlPos.m_nEndPos - UrlPos.m_nStartPos);
m_PosArr.push_back(UrlPos);
}
catch(...)
{
// Couldn't append Url
assert(0);
}
}
private:
CUrlPostionArr& m_PosArr;
LPCSTR m_nCurrentOffset;
};
class CUrlParser : public grammar<CUrlParser>
{
public:
CUrlParser ( )
{
}
CUrlParser& operator = (const CUrlParser& ) {};
template <typename ScannerT>
struct definition
{
definition ( const CUrlParser& );
rule<ScannerT> m_UrlExp
, m_HttpPref
, m_WorldWideWeb
, m_UrlName
, m_UrlNamePart
, m_DomainName
, m_SepDot
, m_SepLine
, m_SimpleEmail
, m_EmailTo
, m_ShortUrlNamePart;
rule<ScannerT> const& start() const;
};
CUrlPostionArr& GetPositionArr ( )
{
return m_PosArr;
}
private:
CUrlPostionArr m_PosArr;
};
int GetTextSize (LPCSTR lpcszText, const LOGFONT& logFnt);
template<typename ScannerT>
CUrlParser::definition<typename ScannerT>::definition (const CUrlParser& )
{
// Creating BNF for URL
m_UrlExp = (
(
(m_HttpPref >> m_WorldWideWeb)
| m_HttpPref
| m_WorldWideWeb
| m_EmailTo
)
>> m_UrlName
>> *(m_SepDot >> m_DomainName)
>> *(m_SepLine>>m_UrlName )
>> *(m_SepDot >> m_DomainName) >>*(m_SepLine)
)
| m_SimpleEmail;
m_HttpPref = str_p("http://")|str_p("HTTP://")| str_p("Http://"); // only 3 variants HtTp - not preffix
m_WorldWideWeb = (str_p("www")|str_p("WWW"))>>m_SepDot;
m_EmailTo = (str_p("Email:") | str_p("email:")) | str_p("EMAIL:") >> *space_p ;
m_ShortUrlNamePart = +( alpha_p | digit_p | ch_p('_')|ch_p(':') | ch_p('-') | ch_p('~') | ch_p ('$')| ch_p ('&')
| ch_p('!')| ch_p('#')| ch_p('%')
| ch_p('^')| ch_p('*') | ch_p('+')| ch_p('|'));
m_UrlNamePart = +(m_ShortUrlNamePart | ch_p('@') );
m_UrlName = m_UrlNamePart ;
m_DomainName = m_UrlNamePart;
m_SepDot = ch_p ('.');
m_SepLine = ch_p('/');
m_SimpleEmail = *(m_ShortUrlNamePart) >>ch_p('@') >>m_ShortUrlNamePart>> *(m_SepDot >> m_ShortUrlNamePart);
}
template<typename ScannerT>
rule<ScannerT> const& CUrlParser::definition<typename ScannerT>::start() const
{
return m_UrlExp;
}
Код тестового модуля:
// Include BOOST Test framework
#include <boost/test/test_tools.hpp>
#include <boost/test/results_reporter.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/output_test_stream.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/detail/unit_test_parameters.hpp>
#include <boost/lexical_cast.hpp>
// STL
#include <iostream>
// include class to test
#include "HyperLinkDetector.h"
// namespace usage
using boost::test_tools::output_test_stream;
using boost::unit_test::test_suite;
using namespace boost::unit_test;
using namespace boost::spirit;
/// Class which performs the testing
class CURLTest
{
typedef CUrlPostionArr::iterator UrlPosIterator;
typedef CUrlPostionArr::const_iterator UrlPosConstIterator;
public:
CURLTest()
{
}
public:
/// Test empty string as URL
void TestEmptyURL()
{
BOOST_MESSAGE("Testing NULL URL")
static const std::string emptyURL("");
InitNewInstances();
DoParse( emptyURL );
UrlPosConstIterator it = m_pPosArr->begin(), endIt = m_pPosArr->end();
// we require HERE that m_pPosArr have to be empty
BOOST_REQUIRE( it == endIt );
}
/// Test simple http adress
void TestSimpleHTTP()
{
static const std::string httpURL("Http://www.google.com");
BOOST_MESSAGE("Testing simple http link " << httpURL.c_str() );
InitNewInstances();
DoParse( httpURL );
// should be one link
BOOST_CHECK( m_pPosArr->size() >= 1 );
BOOST_REQUIRE( m_pPosArr->begin()->m_strUrl == httpURL );
}
/// Test URL's inside the text adn correct URL positions
void TestTextWithLinks()
{
static const std::string textWithURL(
"Some texts 12345656778,@#&^$#@&* $!)(@$*# $%&*@ #^ http://yandex.ru ::?/sdfsdkjfkhsdf---:::/// ftp://81.3.180.101:5555/scripts/ *#&$*#&$ "
);
BOOST_MESSAGE("Testing URL's inside text: " << textWithURL);
InitNewInstances();
DoParse( textWithURL );
BOOST_CHECK( m_pPosArr->size() >= 2 );
// first link iterator
UrlPosConstIterator it = m_pPosArr->begin();
// second link iterator
UrlPosConstIterator it2( ++it );
BOOST_MESSAGE("Test first URL pos");
BOOST_CHECK( it->m_nStartPos == 51 && it->m_nEndPos == 76 );
BOOST_MESSAGE("Test first URL contents");
BOOST_CHECK( it->m_strUrl == "http://yandex.ru" );
BOOST_MESSAGE("Test second URL pos");
BOOST_CHECK( it->m_nStartPos == 105 && it->m_nEndPos == 135 );
BOOST_MESSAGE("Test second URL contents");
BOOST_CHECK( it->m_strUrl == "ftp://81.3.180.101:5555/scripts/" );
}
void TestNotFullURLs()
{
static const std::string wronghURL(
"www://dfdfdf http:\\fsdff/dfdf httP\\dfsd.ru email:erdfs@df"
);
BOOST_MESSAGE("Testing wrong URL's" << wronghURL);
InitNewInstances();
DoParse( textWithURL );
BOOST_REQUIRE( m_pPosArr->size() == 0 );
}
protected:
void InitNewInstances()
{
BOOST_
m_pURLParser.reset( new CUrlParser() );
m_pPosArr.reset( new CUrlPostionArr() );
}
void DoParse( const std::string& strToParse )
{
parse(
strToParse.c_str(),
*((*m_pURLParser)[PushUrlPos(*m_pPosArr,strToParse.c_str())] | anychar_p)
);
}
private:
/// This is the Class to test !!!
std::auto_ptr<CUrlParser> m_pURLParser;
/// Helper member to hold parsed data
std::auto_ptr<CUrlPostionArr> m_pPosArr;
};
test_suite* Init_unit_test_suite( int = 0, char* [] = 0) {
// Create the test Suite instance
test_suite* test= BOOST_TEST_SUITE( "URL Parser test exmaple" );
// Create the instance of the test class
boost::shared_ptr<CURLTest> instancePtr( new CURLTest() );
// add test functions
test->add( BOOST_CLASS_TEST_CASE( &CURLTest::TestEmptyURL, instancePtr ) );
test->add( BOOST_CLASS_TEST_CASE( &CURLTest::TestSimpleHTTP, instancePtr ) );
test->add( BOOST_CLASS_TEST_CASE( &CURLTest::TestTextWithLinks, instancePtr ) );
test->add( BOOST_CLASS_TEST_CASE( &CURLTest::TestNotFullURLs, instancePtr ) );
return test;
}
/// main execution point
int main(int, char* [])
{
// Set the output to file and setup Test framework
#define PATTERN_FILE_NAME "result_report_test.pattern"
std::string pattern_file_name(
argc == 1 ? (runtime_config::save_pattern() ? PATTERN_FILE_NAME : "./test_files/" PATTERN_FILE_NAME )
: argv[1] );
output_test_stream test_output( pattern_file_name, !runtime_config::save_pattern() );
results_reporter::set_stream( test_output );
// Create test Suite
test_suite* pTestSuite = Init_unit_test_suite( );
// Run tests
framework::run( pTestSuite );
return 0;
}
Результаты тестирования:
Содержание выходного файла:
Test suite "URL Parser test exmaple”
9 assertions out of 9 passed
4 test cases out of 4 passed
<TestResult><TestSuite name=" URL Parser test exmaple" result="passed" assertions_passed="9" assertions_failed="0" expected_failures="1" test_cases_passed="4" test_cases_failed="0" test_cases_skipped="0"></TestSuite></TestResult>