Help me bij het maken van een aangepaste C++-raamwerk voor unittests
description
Door een aangepast unittest-ramenwerk te ontwikkelen, kan ik ervoor zorgen dat mijn C++-code grondig wordt getest, een hoge codekwaliteit behouden en problemen snel identificeren tijdens de ontwikkeling.
prompt
try_prompt
Help me bij het ontwerpen en implementeren van een aangepast raamwerk voor unittests in C++. Ik wil functies opnemen zoals testgevalbeheer, assertiebehandeling en rapport ... more
generate_helper
...
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hieronder geef ik een basisstructuur voor een zelfgemaakt unittest-raamwerk in C++, gericht op assertions en testrapportage. Dit voorbeeld bevat:
- Een eenvoudige manier om tests te definiëren en uit te voeren
- Assertiemethoden
- Rapportage van testresultaten
---
**1. Basisstructuur van het raamwerk**
```cpp
#include <iostream>
#include <vector>
#include <string>
struct TestResult {
std::string testnaam;
bool geslaagd;
std::string foutmelding;
};
class TestSuite {
private:
std::vector<TestResult> resultaten;
public:
void voegTestToe(const std::string& naam, void(*testfunctie)()) {
// Voer de test uit en registreer resultaat
try {
testfunctie();
resultaten.push_back({naam, true, ""});
} catch (const std::string& fout) {
resultaten.push_back({naam, false, fout});
} catch (...) {
resultaten.push_back({naam, false, "Onbekende fout"});
}
}
void rapportage() const {
int geslaagdCount = 0;
for (const auto& res : resultaten) {
if (res.geslaagd) {
std::cout << "[PASSED] " << res.testnaam << std::endl;
geslaagdCount++;
} else {
std::cout << "[FAILED] " << res.testnaam << " - Fout: " << res.foutmelding << std::endl;
}
}
std::cout << "\nTotaal tests: " << resultaten.size()
<< ", Geslaagd: " << geslaagdCount
<< ", Gefaald: " << resultaten.size() - geslaagdCount << std::endl;
}
};
```
---
**2. Assertiemethoden**
```cpp
void assertEquals(int verwachte, int werkelijke, const std::string& message = "") {
if (verwachte != werkelijke) {
throw "assertEquals gefaald: " + message + " (verwacht " + std::to_string(verwachte) + ", gevonden " + std::to_string(werkelijke) + ")";
}
}
void assertTrue(bool conditie, const std::string& message = "") {
if (!conditie) {
throw "assertTrue gefaald: " + message;
}
}
```
---
**3. Voorbeeld testgevallen**
```cpp
void testOptellen() {
int resultaat = 2 + 2;
assertEquals(4, resultaat, "Optellen test");
}
void testBoolean() {
bool waarde = (5 > 3);
assertTrue(waarde, "Vergelijking 5 > 3");
}
```
---
**4. Main functie om tests uit te voeren**
```cpp
int main() {
TestSuite suite;
suite.voegTestToe("Test Optellen", &testOptellen);
suite.voegTestToe("Test Boolean", &testBoolean);
suite.rapportage();
return 0;
}
```
---
**Samenvatting:**
- Definieer een `TestSuite` voor het beheren van testcases en rapportage.
- Gebruik functies zoals `assertEquals` en `assertTrue` voor assertions.
- Voeg tests toe met `voegTestToe` en voer de rapportage uit.
Wil je meer functies toevoegen, zoals setup/teardown, parameterized tests, of meer uitgebreide rapportages?
provider: deepseek
model: deepseek-chat
Zeker! Ik help je bij het ontwerpen van een eenvoudig maar krachtig unittestraamwerk in C++. Hier is een complete implementatie met de gevraagde functies:
## Basisstructuur van het raamwerk
```cpp
// test_framework.h
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
class TestCase {
private:
std::string name;
bool passed;
std::string failure_message;
public:
TestCase(const std::string& test_name) : name(test_name), passed(true) {}
virtual void run() = 0;
const std::string& getName() const { return name; }
bool isPassed() const { return passed; }
const std::string& getFailureMessage() const { return failure_message; }
protected:
void assertTrue(bool condition, const std::string& message = "") {
if (!condition) {
passed = false;
failure_message = message.empty() ? "Assertion failed: expected true" : message;
}
}
void assertFalse(bool condition, const std::string& message = "") {
assertTrue(!condition, message.empty() ? "Assertion failed: expected false" : message);
}
template<typename T>
void assertEquals(const T& expected, const T& actual, const std::string& message = "") {
if (expected != actual) {
passed = false;
std::ostringstream oss;
oss << (message.empty() ? "Assertion failed" : message)
<< ": expected '" << expected << "', got '" << actual << "'";
failure_message = oss.str();
}
}
void assertThrows(void (*function)(), const std::string& expected_exception = "") {
try {
function();
passed = false;
failure_message = "Expected exception was not thrown";
} catch (const std::exception& e) {
if (!expected_exception.empty() && expected_exception != typeid(e).name()) {
passed = false;
failure_message = "Wrong exception type thrown";
}
} catch (...) {
if (!expected_exception.empty()) {
passed = false;
failure_message = "Wrong exception type thrown";
}
}
}
};
class TestSuite {
private:
std::string suite_name;
std::vector<TestCase*> test_cases;
public:
TestSuite(const std::string& name) : suite_name(name) {}
void addTestCase(TestCase* test_case) {
test_cases.push_back(test_case);
}
void runAll() {
std::cout << "Uitvoeren testsuite: " << suite_name << std::endl;
std::cout << "=========================================" << std::endl;
int passed_count = 0;
int total_count = test_cases.size();
for (auto test_case : test_cases) {
test_case->run();
if (test_case->isPassed()) {
std::cout << "✓ PASS: " << test_case->getName() << std::endl;
passed_count++;
} else {
std::cout << "✗ FAIL: " << test_case->getName() << std::endl;
std::cout << " Reden: " << test_case->getFailureMessage() << std::endl;
}
}
std::cout << "=========================================" << std::endl;
std::cout << "Resultaat: " << passed_count << "/" << total_count << " geslaagd" << std::endl;
std::cout << std::endl;
}
~TestSuite() {
for (auto test_case : test_cases) {
delete test_case;
}
}
};
// Macro's voor gemakkelijke testdefinitie
#define TEST_CASE(test_name) \
class test_name##_Test : public TestCase { \
public: \
test_name##_Test() : TestCase(#test_name) {} \
void run() override; \
}; \
void test_name##_Test::run()
#define ADD_TEST(suite, test_name) \
suite.addTestCase(new test_name##_Test())
```
## Voorbeeldgebruik
```cpp
// example_tests.cpp
#include "test_framework.h"
#include <cmath>
// Eenvoudige wiskundige functies om te testen
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
double divide(double a, double b) {
if (b == 0) throw std::invalid_argument("Deling door nul");
return a / b;
}
// Testgevallen
TEST_CASE(TestAddition) {
assertEquals(5, add(2, 3), "2 + 3 moet 5 zijn");
assertEquals(0, add(-1, 1), "-1 + 1 moet 0 zijn");
assertEquals(-5, add(-2, -3), "-2 + -3 moet -5 zijn");
}
TEST_CASE(TestMultiplication) {
assertEquals(6, multiply(2, 3), "2 * 3 moet 6 zijn");
assertEquals(0, multiply(5, 0), "5 * 0 moet 0 zijn");
assertEquals(-6, multiply(2, -3), "2 * -3 moet -6 zijn");
}
TEST_CASE(TestDivision) {
assertEquals(2.0, divide(6.0, 3.0), "6.0 / 3.0 moet 2.0 zijn");
assertEquals(0.5, divide(1.0, 2.0), "1.0 / 2.0 moet 0.5 zijn");
// Test op uitzondering
assertThrows([]() { divide(5.0, 0.0); }, "Deling door nul moet uitzondering gooien");
}
TEST_CASE(TestBooleanAssertions) {
assertTrue(5 > 3, "5 moet groter zijn dan 3");
assertFalse(2 == 3, "2 mag niet gelijk zijn aan 3");
assertTrue(true, "true moet true zijn");
}
// Hoofdfunctie om alle tests uit te voeren
int main() {
TestSuite math_suite("Wiskunde Tests");
ADD_TEST(math_suite, TestAddition);
ADD_TEST(math_suite, TestMultiplication);
ADD_TEST(math_suite, TestDivision);
ADD_TEST(math_suite, TestBooleanAssertions);
math_suite.runAll();
return 0;
}
```
## Uitgebreide rapportage-uitvoer
```cpp
// advanced_reporting.h
#include <chrono>
class AdvancedTestSuite : public TestSuite {
private:
std::chrono::high_resolution_clock::time_point start_time;
public:
AdvancedTestSuite(const std::string& name) : TestSuite(name) {}
void runAll() {
start_time = std::chrono::high_resolution_clock::now();
std::cout << "🧪 TESTSUITE: " << suite_name << std::endl;
std::cout << "═════════════════════════════════════════" << std::endl;
int passed_count = 0;
int total_count = test_cases.size();
for (auto test_case : test_cases) {
auto test_start = std::chrono::high_resolution_clock::now();
test_case->run();
auto test_end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(test_end - test_start);
if (test_case->isPassed()) {
std::cout << "✅ PASS: " << test_case->getName()
<< " (" << duration.count() << " μs)" << std::endl;
passed_count++;
} else {
std::cout << "❌ FAIL: " << test_case->getName()
<< " (" << duration.count() << " μs)" << std::endl;
std::cout << " 📝 " << test_case->getFailureMessage() << std::endl;
}
}
auto end_time = std::chrono::high_resolution_clock::now();
auto total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
std::cout << "═════════════════════════════════════════" << std::endl;
std::cout << "📊 SAMENVATTING:" << std::endl;
std::cout << " Geslaagd: " << passed_count << "/" << total_count << std::endl;
std::cout << " Tijd: " << total_duration.count() << " ms" << std::endl;
if (passed_count == total_count) {
std::cout << "🎉 ALLE TESTS GESLAAGD!" << std::endl;
} else {
std::cout << "💥 " << (total_count - passed_count) << " TEST(S) GEFAALD!" << std::endl;
}
std::cout << std::endl;
}
};
```
## Compilatie en uitvoer
```bash
# Compileren
g++ -std=c++11 -o tests example_tests.cpp
# Uitvoeren
./tests
```
**Verwachte uitvoer:**
```
🧪 TESTSUITE: Wiskunde Tests
═════════════════════════════════════════
✅ PASS: TestAddition (45 μs)
✅ PASS: TestMultiplication (32 μs)
✅ PASS: TestDivision (28 μs)
✅ PASS: TestBooleanAssertions (15 μs)
═════════════════════════════════════════
📊 SAMENVATTING:
Geslaagd: 4/4
Tijd: 120 ms
🎉 ALLE TESTS GESLAAGD!
```
## Belangrijke kenmerken:
1. **Testgevalbeheer**: Hiërarchische structuur met TestSuite en TestCase
2. **Assertiebehandeling**: Verschillende assert-types (true, false, equals, exceptions)
3. **Rapportage**: Gedetailleerde uitvoer met succes/falen en timing
4. **Uitbreidbaar**: Eenvoudig nieuwe asserties en rapportagefuncties toe te voegen
5. **Gebruiksvriendelijk**: Macro's voor eenvoudige testdefinitie
Dit raamwerk biedt een solide basis die je verder kunt uitbreiden met functies zoals setup/teardown, testfixtures, parallel testen, of XML-rapportage!

