Iteracyjny test jednostkowy metody klasy
Stronę tą wyświetlono już: 1008 razy
Do celów przykładowych załóżmy, że dla pewnej klasy głównej, która steruje pewnym sygnałem konieczne jest opracowanie modelu jego sterowaniem. Model ten może istnieć w różnych postaciach testowych więc będzie wygodnie opracować klasę dziedziczącą po jednym interfejsie. Oto przykład takiej właśnie klasy:
- // Pierwsza klasa do przetestowania
- class IterableChangeDisplay : public IIterableChangeValueModelTesting{
- public:
- virtual void iterableChengeDisplay(uint32_t &start, uint32_t &end, uint8_t &wsp){
- if(wsp){
- start = std::ceil(qreal(end - start) / wsp) + start;
- }else{
- start = end;
- }
- }
- };
- // Druga klasa do przetestowania
- class IterableChangeDisplay2 : public IIterableChangeValueModelTesting{
- public:
- virtual void iterableChengeDisplay(uint32_t &start, uint32_t &end, uint8_t &wsp){
- if(wsp){
- start = (end - start) / wsp + start;
- }else{
- start = end;
- }
- }
- };
Jak widać klasy IterableChangeDisplay i IterableChangeDisplay2 dziedziczą po interfejsie IIterableChangeValueModelTesting, którego konstrukcja jest następująca:
- class IIterableChangeValueModelTesting : public IIterableChangeValueModel, ITesting{
- public:
- virtual void testing(enum testing_flags flag = testing_flags::DISPLAY_ALL, QHtmlObject* html = 0, std::unordered_map<QString, long> *parameters = 0){
- uint32_t start = 100;
- uint32_t end = 1000;
- uint8_t wsp = 100;
- QHtmlObject* body = 0;
- if(html){
- body = html->getElementsByName("body")[0];
- }
- if(body)
- body
- ->addHtmlChild(QHtmlObject::createH1("Testing class: " + QString(typeid(*this).name())));
- QString data = "=======================================================\nTesting class: " +
- QString(typeid(*this).name()) + "\n"
- "=======================================================\n\n";
- qDebug() << data;
- for(wsp = 0; wsp <= 100; wsp ++){
- start = 100;
- if(parameters){
- auto search = parameters->find("start");
- if(search != parameters->end()){
- start = search->second;
- }
- search = parameters->find("end");
- if(search != parameters->end()){
- end = search->second;
- }
- }
- if(body)
- body
- ->addHtmlChild(QHtmlObject::createH2("Testing for parameters:"))
- .addHtmlChild(QHtmlObject::createParagraph("start = " + QString::number(start)))
- .addHtmlChild(QHtmlObject::createParagraph("end = " + QString::number(end)))
- .addHtmlChild(QHtmlObject::createParagraph("wsp = " + QString::number(wsp)));
- data = "Testing for parameters:\n"
- "start = " + QString::number(start) + "\n"
- "end = " + QString::number(end) + "\n"
- "wsp = " + QString::number(wsp) + "\n";
- qDebug() << data;
- for(int i = 0; i < 1000; i++){
- iterableChengeDisplay(start, end, wsp);
- if(start == end){
- if(flag == testing_flags::DISPLAY_ALL){
- if(body)
- body
- ->addHtmlChild(
- QHtmlObject::createH3("Looks like algorythm works fine! End parameters for iteration: " + QString::number(i + 1) + ":")
- .addAttributes("class", "good")
- )
- .addHtmlChild(QHtmlObject::createParagraph("start = " + QString::number(start)))
- .addHtmlChild(QHtmlObject::createParagraph("end = " + QString::number(end)))
- .addHtmlChild(QHtmlObject::createParagraph("wsp = " + QString::number(wsp)));
- data = "Looks like algorythm works fine! End parameters:\n"
- "Parameters for iteration nr. " + QString::number(i + 1) + "\n"
- "start = " + QString::number(start) + "\n"
- "end = " + QString::number(end) + "\n"
- "wsp = " + QString::number(wsp) + "\n";
- qDebug() << data;
- }
- break ;
- }
- }
- if(start != end){
- if(body)
- body
- ->addHtmlChild(
- QHtmlObject::createH3("Looks like algorythm not works too good for 1000 iterations:")
- .addAttributes("class", "bad")
- )
- .addHtmlChild(QHtmlObject::createParagraph("start = " + QString::number(start)))
- .addHtmlChild(QHtmlObject::createParagraph("end = " + QString::number(end)))
- .addHtmlChild(QHtmlObject::createParagraph("wsp = " + QString::number(wsp)));
- data = "Looks like algorythm not works too good for 1000 iterations:\n"
- "start = " + QString::number(start) + "\n"
- "end = " + QString::number(end) + "\n"
- "wsp = " + QString::number(wsp) + "\n";
- qDebug() << data;
- }
- }
- }
- };
Wewnątrz interfejsu IIterableChangeValueModelTesting znajduje się jedynie metoda testing czysto wirtualna, która pozwala na przeprowadzenie testu działania algorytmu dla wartości:
- wsp - zawierającej się w zakresie od 0 do 100;
- start - ustawionej domyślnie na wartość 100;
- end - ustawionej domyślnie na wartość 1000;
- i - wewnętrznie określona liczba iteracji na 1000
Metoda testing tworzy plik .html z raportem o przebiegu testowania wyświetlając równocześnie te dane na ekranie. Jak widać interfejs ten dziedziczy po dwóch innych interfejsach: IIterableChangeValueModel - dostarcza czysto wirtualnej metody przeznaczonej do modyfikacji sygnału; ITesting - dostarcza czysto wirtualnej metody do testowania funkcji modyfikacji sygnału.
- class ITesting{
- public:
- virtual void testing(enum testing_flags flag = testing_flags::DISPLAY_ALL, QHtmlObject* html = 0, std::unordered_map<QString, long> *parameters = 0) = 0;
- virtual ~ITesting(){};
- };
- class IIterableChangeValueModel{
- public:
- virtual void iterableChengeDisplay(uint32_t &start, uint32_t &end, uint8_t &wsp) = 0;
- virtual ~IIterableChangeValueModel(){}
- };
Klasa QHtmlObject użyta jako parametr metody testing została napisana przeze mnie do generowania kodu HTML ponieważ na moje potrzeby wolę tworzyć plik raportu w bardziej przystępnej i sformatowanej formie. Pierwszy parametr wcześniej wspomnianej metody przyjmuje wartość jednej z dostępnych flag:
- enum testing_flags{
- DISPLAY_ERROR_ONLY,
- DISPLAY_ALL
- };
Klasa IterableChangeDisplay2 ma błąd wewnętrzny nie uwzględniający działania na liczbach całkowitych, natomiast klasa IterableChangeDisplay już takiego błędu jest pozbawiona. Oto kod wykorzystujący system testujący do obu tych klas:
- IterableChangeDisplay2 model2;
- IterableChangeDisplay model1;
- QFile file("test.html");
- file.open(QIODevice::WriteOnly);
- QTextStream textStream(&file);
- std::unordered_map<QString, long> parameters = {{"start", 0}, {"end", 500}};
- parameters.insert( std::make_pair<QString, long>("wsp", 100) );
- QHtmlPage html("Testing raport");
- html.addLocalStyle( ".bad{ color: red;} .good{ color: green; }");
- model2.testing(testing_flags::DISPLAY_ALL, &html, ¶meters);
- model1.testing(testing_flags::DISPLAY_ALL, &html, ¶meters);
- textStream << html;
- file.close();
Raport, jaki powyższy kod utworzy jest dość długi, ale dla celów poglądowych zamieszczam go tutaj. Jak wynika z tegoż raportu test dla obiektu klasy IterableChangeDisplay2 zakończył się powodzeniem jedynie w dwóch pierwszych przypadkach, a to dlatego, że nie uwzględniono operacji na liczbach całkowitych. Ten sam test dla obiektu klasy IterableChangeDisplay kończy się pomyślnie dla wszystkich testowanych wartości.
