HomeMathEmailBlogGitHub

C Unit Testing

2024-07-12

During my second college semester studying pure math, I was taking a very entry level Computer Science course that went over the basics of Java and C++. The only homeworks were programs that would be due in about a week or two, so not too complex, but also not "Hello, World".

Because of my extreme programming brainwashing, I needed to write all of homeworks with TDD. For the Java half of the course, the decision to use JUnit was pretty straightforward, especially because of my experience using it during my apprenticeship (see math language, HTTP Server).

However, during the C++ half of the course, the decision of what unit testing framework I would use was not so obvious. I did have some parameters, though:

After some light Googling, I was surprised to find nothing that met these criteria. So, I decided to make it myself.

specc

specc is what I came up with and it meets all of the criteria. It's written entirely in C, but also works for C++. The framework is modeled after Micah Martin's speclj for Clojure (which is based on RSpec). Here's some specc example code:

// in file example.c
#include "specc.h"

module(simple, {
  
  describe("simple test", {
    
    it("this is what a passing test looks like", {
      should(1 == 1);
    });

    it("failing boolean test", {
      should(1 == 0);
    });
  });
});

Then I compile with specc:

g++ -c specc.c
g++ -c example.c
g++ specc.o example.o
./a.out

And here's the output: example output

And that's it. That's all you have to do.

If you're curious about how it works, I'll try to shed some light:

Q: How does the program even run? You never wrote a main function.
A: specc.c contains the entry point which runs the tests.

Q: But how does specc.c know what functions to call? You never copied the tests into a call list.
A: All of the functions shown in the example are really macros. The module macro defines a function with the given name and body. Then, module uses __attribute__((constructor)) __construct_ to add that newly defined function to a linked list of functions that specc.c calls in main. This is the only way I know is possible to call 'dynamically' defined functions in C. It also shifts the problem of dependency load order to the compiler.

Q: I have another question
A: It's open source