Actually this tutorial is organized in the wrong order. It should not have
started with how to make objects but with how to test them. Before you
write some code, you must write a test that verifies the code. So for every
piece of code you have an automated test that verifies its correctness.
This is even more important in OBC programming. Since OBC objects do not
have a type, the compiler will not help you in detecting errors. It is your
obligation to write your error testing software. This way you can also test
a lot more, than a compiler ever could.
test.h and test.c offer a simple testing framework. Here is an example
how such a test looks:
carT.c
#include "../obc/test.h"
#include "car.h"
static void accelerate() {
Car car = car_create();
testEqual(0, car_getSpeed(car));
car_accelerate(car);
test(0 < car_getSpeed(car), "car did not accelerate");
car_destroy(car);
}
Test car_test() {
Test t = test_create("Car", test_init, test_clean);
test_add(t, accelerate);
return t;
}
main.c
...
#include "../obc/test.h"
Test car_test();
Test boat_test();
Test tests() {
Test t = test_create("OBC demo", NULL, NULL);
test_addTest(t, car_test() );
test_addTest(t, boat_test() );
return t;
}
int main(){
test_run(tests, 2);
...
}
Define functions that test an aspect of an object (ex. accelerate() ). Use
the macro test(condition, comment) to do so.
Add the functions to a unit test that tests the
whole object functionality (ex. car_test() ). Add all unit tests to a main
test unit ( tests() ). Run this tests at the BEGINNING of main with
test_run(tests, 2); . This way your objects are tested after each modification.
The test macros can also be used without tests. Then they behave like normal
asserts. The are turned off when NDEBUG is defined. More test macros are:
vehicleT.c
#include "../obc/test.h"
#include "../obc/objI.h"
#include "vehicleI.h"
static void accelerate() {
Obj vehicle = test_createObj("Vehicle");
vehicle_accelerate(vehicle);
test(0 < vehicle_getSpeed(vehicle), "vehicle did not accelerate");
obj_destroy(vehicle);
}
Test vehicle_test(const char* name, TestObjConstructor constructor ) {
Test t = test_create(name, NULL, NULL);
test_addObjConstructor(t, "Vehicle", constructor);
test_add(t, accelerate);
return t;
}
carT.c
...
static Test car_testBase() {
Test t = test_create("Car base", NULL, NULL);
test_add(t, creation);
test_add(t, accelerate);
test_add(t, brake);
return t;
}
Test car_test() {
Test t = test_create("Car", NULL, NULL);
test_addTest(t, car_testBase());
test_addTest(t, vehicle_test("Car vehicle", (TestObjConstructor)car_create));
return t;
}
Note, that a test can not hold test functions and sub tests at the same time. For this reason a car sub test "Car base" has been introduced to hold the function tests for the car.