Générateur de unit test

Description

Inspiré des unit test que fait eclipse en java.

Cette source vous permettra de générer des fichiers unittest.h et unittest.cpp à joindre à tous vos projets pour tester vos classes. Elle permet aussi de générer des fichiers de unit test préformatés pour chacune de vos classes. Il ne reste alors qu'à écrire les tests à l'aide des fonction assertTrue(bool), assertFalse(bool) ou assertEquals(const T&,const T&).
Il suffit alors de runner le test qui s'occupe de l'affichage.

Un exemple complet est fournit dans le zip.

Pour des questions ou des notifications de bug n'hésitez pas à me mailer !

Bon amusement ! :-)

Source / Exemple :


/*

  • UnitTestGenerator : main.cpp
  • Created by Christophe Dumeunier on 25/03/08.
  • Copyright 2008 Christophe Dumeunier. All rights reserved.
  • This application is free; you can redistribute it and/or modify
  • it under the terms of the GNU General Public License as published by
  • the Free Software Foundation; either version 2 of the License, or
  • (at your option) any later version.
  • Contact: legrandduche@gmail.com (in french if possible)
*
  • /
#include <iostream> #include <fstream> #include <list> using namespace std; void createUnitTestLib() { ofstream f1("unittest.h"); f1 << "/*" << endl << " * unittest.h" << endl << " * " << endl << " * Created by Christophe Dumeunier on 25/03/08." << endl << " * Generated by UnitTestGenerator." << endl << " * Copyright 2008 Christophe Dumeunier. All rights reserved." << endl << " * This file is free; you can redistribute it and/or modify" << endl << " * it under the terms of the GNU General Public License as published by" << endl << " * the Free Software Foundation; either version 2 of the License, or" << endl << " * (at your option) any later version." << endl << " * " << endl << " * Contact: legrandduche@gmail.com (in french if possible)" << endl << " * " << endl << " */" << endl << endl << "#ifndef UNITTEST_H" << endl << "#define UNITTEST_H" << endl << endl << "#include <iostream>" << endl << "#include <string.h>" << endl << "#include <list>" << endl << "using namespace std;" << endl << endl << "class UnitTest" << endl << "{" << endl << " private:" << endl << " int nbr_valid;" << endl << " int nbr_unvalid;" << endl << " list<int> failure;" << endl << " " << endl << " public:" << endl << " UnitTest();" << endl << " ~UnitTest();" << endl << " " << endl << " void fail();" << endl << " void success();" << endl << " " << endl << " void assertTrue(bool);" << endl << " void assertFalse(bool);" << endl << " template <class T> void assertEquals(const T& value,const T& test)" << endl << " {" << endl << " if(value==test)" << endl << " success();" << endl << " else" << endl << " fail();" << endl << " }" << endl << " template <class T> void assertNotEquals(const T& value,const T& test)" << endl << " {" << endl << " if(!(value == test))" << endl << " success();" << endl << " else" << endl << " fail();" << endl << " }" << endl << " void assertNull(void*);" << endl << " void assertNotNull(void*);" << endl << " void assertSame(void*,void*);" << endl << " void assertNotSame(void*,void*);" << endl << " " << endl << " bool valid() const;" << endl << " void print(const string&);" << endl << " void reinit();" << endl << "};" << endl << endl << "#endif" << endl; f1.close(); ofstream f2("unittest.cpp"); f2 << "/*" << endl << " * unittest.cpp" << endl << " * " << endl << " * Created by Christophe Dumeunier on 25/03/08." << endl << " * Generated by UnitTestGenerator." << endl << " * Copyright 2008 Christophe Dumeunier. All rights reserved." << endl << " * This file is free; you can redistribute it and/or modify" << endl << " * it under the terms of the GNU General Public License as published by" << endl << " * the Free Software Foundation; either version 2 of the License, or" << endl << " * (at your option) any later version." << endl << " * " << endl << " * Contact: legrandduche@gmail.com (in french if possible)" << endl << " * " << endl << " */" << endl << endl << "#include \"unittest.h\"" << endl << endl << "UnitTest::UnitTest()" << endl << "{" << endl << " nbr_valid = 0;" << endl << " nbr_unvalid = 0;" << endl << "}" << endl << endl << "UnitTest::~UnitTest()" << endl << "{" << endl << "}" << endl << endl << "void UnitTest::fail()" << endl << "{" << endl << " nbr_unvalid++;" << endl << " failure.push_back(nbr_valid + nbr_unvalid);" << endl << "}" << endl << endl << "void UnitTest::success()" << endl << "{" << endl << " nbr_valid++;" << endl << "}" << endl << endl << "void UnitTest::assertTrue(bool test)" << endl << "{" << endl << " if(test)" << endl << " success();" << endl << " else" << endl << " fail();" << endl << "}" << endl << endl << "void UnitTest::assertFalse(bool test)" << endl << "{" << endl << " if(!test)" << endl << " success();" << endl << " else" << endl << " fail();" << endl << "}" << endl << endl << "void UnitTest::assertNull(void* ptr)" << endl << "{" << endl << " if(ptr == NULL)" << endl << " success();" << endl << " else" << endl << " fail();" << endl << "}" << endl << endl << "void UnitTest::assertNotNull(void* ptr)" << endl << "{" << endl << " if(!(ptr == NULL))" << endl << " success();" << endl << " else" << endl << " fail();" << endl << "}" << endl << endl << "void UnitTest::assertSame(void* ptr1,void* ptr2)" << endl << "{" << endl << " if(ptr1 == ptr2)" << endl << " success();" << endl << " else" << endl << " fail();" << endl << "}" << endl << endl << "void UnitTest::assertNotSame(void* ptr1,void* ptr2)" << endl << "{" << endl << " if(!(ptr1 == ptr2))" << endl << " success();" << endl << " else" << endl << " fail();" << endl << "}" << endl << endl << "bool UnitTest::valid() const" << endl << "{" << endl << " if(nbr_unvalid == 0)" << endl << " return true;" << endl << " else" << endl << " return false;" << endl << "}" << endl << endl << "void UnitTest::print(const string& s)" << endl << "{" << endl << " cout << \" Valid Test for \" << s << \" : [\" << nbr_valid << \"/\" << nbr_valid + nbr_unvalid << \"].\";" << endl << " if(nbr_unvalid == 0)" << endl << " cout << \" Test is ok.\" << endl;" << endl << " else" << endl << " {" << endl << " cout << \" TEST IS WRONG !!!\" << endl" << endl << " << \" Failure(s) on test(s) \";" << endl << " list<int>::iterator it;" << endl << " for(it=failure.begin();it!=failure.end();it++)" << endl << " cout << \" \" << (*it);" << endl << " cout << \".\" << endl;" << endl << " }" << endl << "}" << endl << endl << "void UnitTest::reinit()" << endl << "{" << endl << " nbr_valid = 0;" << endl << " nbr_unvalid = 0;" << endl << " failure.clear();" << endl << "}" << endl; f2.close(); } void createNewUnitTest(const string& file_name,const string& class_name,list<string>& function_list) { string min_class_name = class_name; if((min_class_name[0] >= 'A') && (min_class_name[0] <= 'Z')) min_class_name[0] += (int)'a' - (int)'A'; string all_maj_class_name = class_name; for(int i=0;i<all_maj_class_name.length();i++) { if((all_maj_class_name[i] >= 'a') && (all_maj_class_name[i] <= 'z')) all_maj_class_name[i] -= (int)'a' - (int)'A'; } string unittest_hfile_name = min_class_name + ".unittest.h"; string unittest_cppfile_name = min_class_name + ".unittest.cpp"; ofstream f1(unittest_hfile_name.c_str()); f1 << "/*" << endl << " * " << unittest_hfile_name << endl << " * " << endl << " * Generated by UnitTestGenerator." << endl << " * Copyright 2008 Christophe Dumeunier. All rights reserved." << endl << " * This file is free; you can redistribute it and/or modify" << endl << " * it under the terms of the GNU General Public License as published by" << endl << " * the Free Software Foundation; either version 2 of the License, or" << endl << " * (at your option) any later version." << endl << " * " << endl << " * Contact: legrandduche@gmail.com (in french if possible)" << endl << " * " << endl << " */" << endl << endl << "#ifndef " << all_maj_class_name << "_UNITTEST_H" << endl << "#define " << all_maj_class_name << "_UNITTEST_H" << endl << endl << "#include \"unittest.h\"" << endl << "#include \"" << file_name << "\"" << endl << endl << "class " << class_name << "UnitTest : private UnitTest" << endl << "{" << endl << " private:" << endl << " //add your variables" << endl << " " << endl << " public:" << endl << " " << class_name << "UnitTest();" << endl << " ~" << class_name << "UnitTest();" << endl << " " << endl << " bool runTest();" << endl << " " << endl << " private:" << endl << " void setUp();" << endl << " void tearDown();" << endl << " " << endl; list<string>::iterator it; for(it=function_list.begin();it!=function_list.end();it++) { string name = (*it); int left_parenth = name.find("("); int length = name.length(); name.erase(left_parenth,length-left_parenth); f1 << " void " << name << "_"; string params = (*it); params.erase(length-1,1); params.erase(0,left_parenth+1); params += ","; if(params == ",") params = "void,"; while(params.length() > 0) { int comma = params.find(","); int length_param = params.length(); string param = params; param.erase(comma,length_param-comma); if((param[0] >= 'a') && (param[0] <= 'z')) param[0] -= (int)'a' - (int)'A'; while(param.find("*") != string::npos) { int paramFindStar = param.find("*"); param.replace(paramFindStar,1,"Ptr"); } while(param.find("&") != string::npos) { int paramFindAnd = param.find("&"); param.replace(paramFindAnd,1,"Ref"); } f1 << param; params.erase(0,comma+1); } f1 << "();" << endl; } f1 << "};" << endl << endl << "typedef void (" << class_name << "UnitTest::*" << class_name << "UnitTestMemberFunctionPointer)(void);" << endl << endl << "#endif" << endl; f1.close(); ofstream f2(unittest_cppfile_name.c_str()); f2 << "/*" << endl << " * " << unittest_cppfile_name << endl << " * " << endl << " * Generated by UnitTestGenerator." << endl << " * Copyright 2008 Christophe Dumeunier. All rights reserved." << endl << " * This file is free; you can redistribute it and/or modify" << endl << " * it under the terms of the GNU General Public License as published by" << endl << " * the Free Software Foundation; either version 2 of the License, or" << endl << " * (at your option) any later version." << endl << " * " << endl << " * Contact: legrandduche@gmail.com (in french if possible)" << endl << " * " << endl << " */" << endl << endl << "#include \"" << unittest_hfile_name << "\"" << endl << endl << class_name << "UnitTest::" << class_name << "UnitTest()" << endl << "{" << endl << " //construct your variables" << endl << "}" << endl << endl << class_name << "UnitTest::~" << class_name << "UnitTest()" << endl << "{" << endl << " //destruct your variables" << endl << "}" << endl << endl << "bool " << class_name << "UnitTest::runTest()" << endl << "{" << endl << " const int run_vector_size = " << (int)function_list.size() << ";" << endl << " " << class_name << "UnitTestMemberFunctionPointer run_vector[run_vector_size] =" << endl << " {" << endl; for(it=function_list.begin();it!=function_list.end();it++) { string name = (*it); int left_parenth = name.find("("); int length = name.length(); name.erase(left_parenth,length-left_parenth); if(it != function_list.begin()) f2 << "," << endl; f2 << " &" << class_name << "UnitTest::" << name << "_"; string params = (*it); params.erase(length-1,1); params.erase(0,left_parenth+1); params += ","; if(params == ",") params = "void,"; while(params.length() > 0) { int comma = params.find(","); int length_param = params.length(); string param = params; param.erase(comma,length_param-comma); if((param[0] >= 'a') && (param[0] <= 'z')) param[0] -= (int)'a' - (int)'A'; while(param.find("*") != string::npos) { int paramFindStar = param.find("*"); param.replace(paramFindStar,1,"Ptr"); } while(param.find("&") != string::npos) { int paramFindAnd = param.find("&"); param.replace(paramFindAnd,1,"Ref"); } f2 << param; params.erase(0,comma+1); } } f2 << endl << " };" << endl << " string string_run_vector[run_vector_size] =" << endl << " {" << endl; for(it=function_list.begin();it!=function_list.end();it++) { if(it != function_list.begin()) f2 << "," << endl; f2 << " \"" << class_name << "::" << (*it) << "\""; } f2 << endl << " };" << endl << " bool validTest = true;" << endl << " cout << \" ------------------------------------------------------------------------------\" << endl" << endl << " << \" Unit Test of class " << class_name << " -- by Christophe Dumeunier\" << endl" << endl << " << \" ------------------------------------------------------------------------------\" << endl;" << endl << " for(int i=0;i<run_vector_size;i++)" << endl << " {" << endl << " setUp();" << endl << " (this->*run_vector[i])();" << endl << " tearDown();" << endl << " validTest = validTest && valid();" << endl << " print(string_run_vector[i]);" << endl << " reinit();" << endl << " }" << endl << " cout << \" ------------------------------------------------------------------------------\" << endl;" << endl << " return validTest;" << endl << "}" << endl << endl << "void " << class_name << "UnitTest::setUp()" << endl << "{" << endl << " //prepare each test" << endl << "}" << endl << endl << "void " << class_name << "UnitTest::tearDown()" << endl << "{" << endl << " //terminate each test" << endl << "}" << endl; for(it=function_list.begin();it!=function_list.end();it++) { string name = (*it); int left_parenth = name.find("("); int length = name.length(); name.erase(left_parenth,length-left_parenth); f2 << endl << "void " << class_name << "UnitTest::" << name << "_"; string params = (*it); params.erase(length-1,1); params.erase(0,left_parenth+1); params += ","; if(params == ",") params = "void,"; while(params.length() > 0) { int comma = params.find(","); int length_param = params.length(); string param = params; param.erase(comma,length_param-comma); if((param[0] >= 'a') && (param[0] <= 'z')) param[0] -= (int)'a' - (int)'A'; while(param.find("*") != string::npos) { int paramFindStar = param.find("*"); param.replace(paramFindStar,1,"Ptr"); } while(param.find("&") != string::npos) { int paramFindAnd = param.find("&"); param.replace(paramFindAnd,1,"Ref"); } f2 << param; params.erase(0,comma+1); } f2 << "()" << endl << "{" << endl << " //make your tests" << endl << "}" << endl; } f2.close(); } int main(int sys_nbr_args,char** sys_args) { cout << endl << endl << " ------------------------------------------------------------------------------" << endl << " Welcome on the UnitTest Generator by Christophe Dumeunier." << endl << " Copyright 2008 Christophe Dumeunier. All rights reserved." << endl << " This application is a free software; you can redistribute it and/or modify" << endl << " it under the terms of the GNU General Public License as published by" << endl << " the Free Software Foundation; either version 2 of the License, or" << endl << " (at your option) any later version." << endl << " ------------------------------------------------------------------------------" << endl << endl << endl; int user; bool finish = false; while(!finish) { cout << endl << " 1. Create unittest.h and unittest.cpp files" << endl << " 2. Create a new UnitTest on a class" << endl << " 3. Quit" << endl << endl; cin >> user; if(user == 1) { createUnitTestLib(); cout << "done." << endl; } else if(user == 2) { string file_name; string class_name; list<string> function_list; cout << " Enter the file name (containing the class, for example: example.h)" << endl; cin >> file_name; cout << " Enter the class name (for example : Example)" << endl; cin >> class_name; bool finish2 = false; while(!finish2) { string function_name = ""; cout << " Add a member function of class " << class_name << " (for example : int myFunction(char,int))" << endl << " -- \"()\" to terminate --" << endl; bool line_readed = false; while(!line_readed) { string temporary_str; cin >> temporary_str; function_name += temporary_str; if(function_name[function_name.length()-1] == ')') line_readed = true; else function_name += ","; } if(function_name == "()") finish2 = true; else function_list.push_back(function_name); } createNewUnitTest(file_name,class_name,function_list); cout << "done." << endl; } else if(user == 3) { finish = true; cout << "Bye !" << endl; } else { cout << "Try again..." << endl; } } cout << endl << endl; return 0; }

Conclusion :


à venir:
  • parseur pour éviter à l'utilisateur de taper les fonctions à la main (et ainsi des risquer des erreur dans le fichier généré)
  • possibilité d'ajouter des unittest à un fichier
  • interface plus sympa que la console ( peut-être un jour... un motivé pour le faire ? :-D )

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.