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:
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:
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.