4

I have recently started trying to use TDD in one of my C++ projects. I am very new at this, and I have some very basic questions regarding to the way unit tests are compiled and used. I am using the Boost.Test library on Linux.

  1. Is it common to compile a single large test program, containing all test suites, for all your units? How about splitting the tests into many smaller independent test programs?

  2. How is linking handled (with make)? Every test program object must be linked with the object file(s) from my source program that contains whatever it is that's being tested. Is there a way to handle this automatically? To be more specific, is there anyway to write a Makefile so that make automatically determines what object files must be linked together to generate a certain unit test program?

Update: My code is organized in many .cpp/.h files, and is currently monolithic (no libraries). The unit tests are in a separate directory, usually in 1-to-1 relationship with the .cpp files from my source tree.

Update 2: Hoping that this will make my question less broad, here is an excerpt from the Makefile I am using:

$(TSTDIR)%.$(TEST): $(OBJDIR)%.$(TEST).$(OBJEXT) $(OBJDIR)%.$(OBJEXT)
    @mkdir -p $(@D)
    @$(CXX) -o $@ $^ $(TSTLIBS)

$(OBJDIR)%.$(OBJEXT): $(SRCDIR)%.$(SRCEXT) $(DEPDIR)%.$(DEPEXT)
    @mkdir -p $(@D)
    @$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $<

$(TEST) is just a marker I am using to differentiate between my unit tests and other files. Note that I am currently linking all test programs with the object file that bears the same name. However this will break if symbols from another object file are also needed.

Update 3: This is an example of what I am talking about in the above paragraph.

MyOtherClass.h:

class MyOtherClass
{
public:
    int Foo();
}

MyOtherClass.cpp:

#include "MyOtherClass.h"

int MyOtherClass::Foo()
{
    return 0;
}

MyClass.h:

#include "MyOtherClass.h"

class MyClass
{
public:
    int Foo();

private:
    MyOtherClass moc_;
}

MyClass.cpp:

#include "MyClass.h"

int MyClass::Foo()
{
    return moc_.Foo();
}

TestMyClass.cpp would test if MyClass::Foo returns 0. Using my current Makefile, this will not compile, as the test program needs to be linked with both MyClass.o and MyOtherClass.o.

Dan Nestor
  • 2,441
  • 1
  • 24
  • 45
  • I disagree with putting this question on hold. I asked a meta question here: https://meta.stackoverflow.com/questions/276879/why-was-this-question-put-on-hold-as-opinion-based - comments from the people who voted are welcome. – Dan Nestor Nov 15 '14 at 13:17
  • 1
    How did you organize your code that should go under test? Do you have static or shared libraries? Do you have only plain source bunch compiled into a monolithic executable? What's your unit testing framework? What hinders you to add another target `test:` to your make file? And many more questions left open here ... There's no right or wrong way to offer you sorry. – πάντα ῥεῖ Nov 15 '14 at 13:46
  • @πάνταῥεῖ Updating the question with the organization of my code. My unit testing framework is clearly stated in the question. Nothing hinders me from adding another target `test:`. My question is what I should write beneath it. – Dan Nestor Nov 15 '14 at 13:50
  • I have read your question (probably missing the boost point), but the most broadest thing is how to set it up with `make`. That well depends on how your code is actually organized, and what's used for building it already. – πάντα ῥεῖ Nov 15 '14 at 13:54
  • @πάνταῥεῖ Although I still think that the broadness of the question will be unaffected by this, I think an useful thing would be for me to give an excerpt of my Makefile. That should answer the concerns you put forward in your previous comment. – Dan Nestor Nov 15 '14 at 13:57
  • If you can match translation unit files under test just by a prefix like e.g. `MyClass.cpp` -> `TestMyClass.cpp` picking up all of the necessary sources to link with the test runner should be a fairly simple task (check make functions for file and directory name substitution). – πάντα ῥεῖ Nov 15 '14 at 14:01
  • @πάνταῥεῖ You commented just as I was appending my Makefile, which does exactly that! :)) However, as I said in the question, this will break if I need symbols from another file, say `MyOtherClass.cpp`. Can I somehow handle this case in my Makefile? – Dan Nestor Nov 15 '14 at 14:05
  • Not with the monolithic approach IMHO. You should have well defined interfaces, and mock classes instead of the real stuff. – πάντα ῥεῖ Nov 15 '14 at 14:07
  • @πάνταῥεῖ Thanks for all the input. I also added a code sample, based on what we discussed earlier. – Dan Nestor Nov 15 '14 at 14:17
  • What's the actual relation between `MyClass` and `MyOtherClass`? You have missed to specify an interface, that makes you independent from the actual `MyOtherClass` implementation. That's a problem of how your code/class hierarchy and relations are organized, not one of the testing environment. – πάντα ῥεῖ Nov 15 '14 at 14:23
  • Apart from `MyClass` has a member of type `MyOtherClass`, what do you need to know? – Dan Nestor Nov 15 '14 at 14:24

1 Answers1

1

I found this excellent answer that was given to a related question.

It's possible to solve the linking problem by using static or dynamic libraries. If the object files being tested are compiled into libraries, then when linking the unit test program, it will pull whatever dependencies it needs from the library.

Community
  • 1
  • 1
Dan Nestor
  • 2,441
  • 1
  • 24
  • 45