At the moment I'm writing a test-driven project, and I stuck in testing the following behaviour.
I got an interface called Menu
to which one can add dynamically entries through an addEntry
-Method. There is another class which contains the Menu
object. Let's call it MenuPresenter
. When a specific method (e.g. someAction(string title)
) is called the MenuPresenter
should instantiate an Entry
object with the received title and add it to the Menu
object. The instantiation of the Entry
object happens in a factory method inside the MenuPresenter
.
The tested behaviour should be WhenSomeActionIsCalledShouldAddAnEntryContainingTitleToMenu
But I don't find the right way to write the test. I figured out two main possibilities to test it, but I actually don't like both of them because of the (later) mentioned disadvantages.
MenuSpy
inheriting from Menu
, which has a getAddedEntry
-Method. Like this you can extract the added Entry
and check the state of the objectEXPECT_TRUE(entry->getTitle() == title);
Disadvantages: To check the state of the Entry
object I have either to extend the API of the Interface with getter-Methods which are only used for testing reasons or to use public member variables. This allow every client get access to the internal structure of each Implementation of Entry
. Thus the clients are coupled to internal structure.
EntryFactory
interface which has amakeEntry(std::string title)
-method. Like this one can implement an EntryFactorySpy
and can check if the makeEntry
-method is called with the correct parameters (title). In another Test we can implement an EntryFactoryStub
which returns a specific Entry
object. Then we can check (via a MenuSpy
) if the MenuPresenter
has added the received entry from the factory to the menu. The instantiation of the Entry
object is then tested in a unit test for a the factory.Disadvantages: Because I test the call of the factory's makeEntry
-method the algorithm of using a factory to create entries is fix. The test is tightly coupled to the internal structure of the MenuPresenter
. Changing the algorithm (e.g. using now the factory method would break the test, without that the expected behaviour of the application breaks.
For application's behaviour it should be unimportant if the MenuPresenter
creates the Entry
itself of if it uses a EntryFactory
. This is why I'd prefer the first way. But I don't want the client's of Entry
to be coupled to the internal structure of Entry
only because of testing reasons.
This is only an example of my problem. In reality the entry not only created with a string. It gets other complex objects as shared_ptr. This is another reason, why I dont want to use public getter-methods. Like this one could extract the complex object from the Entry
and change it (Yes, I could give out a const shared_ptr, but this seems to be not a good practice to me.)
The Question is, does anyone know a testing pattern or a solution that adresses my problem? Meaning testing if a correct Entry
object is added to the Menu
object without being coupled to tight to the algorithm or the internal structure of Entry
?
I'm a java developer, I never exercise TDD in c++, but I maybe can describe what you want to test as you mentioned above.
In Classic TDD, the MenuPresenter
should be more like a mini-integration test as Martin Fowler has said in Test Isolation.
In essence classic xunit tests are not just unit tests, but also mini-integration tests. As a result many people like the fact that client tests may catch errors that the main tests for an object may have missed, particularly probing areas where classes interact.
In Classic TDD Use real objects if possible and a Test Double if it's awkward to use the real thing when testing MenuPresenter
. So ask yourself what expected effect happens when an Entry
added in a Menu
. testing Menu
will be adding an titled Entry
only is meaningless, you should test what is behavior effected after an Entry
added.let's say an Entry
added will display as a titled MenuItem
, so you just assert real Menu
object that whether displayed a MenuItem
with expected title.
Indeed, WhenSomeActionIsCalledShouldAddAnEntryContainingTitleToMenu
test is already exposing someAction
implementation details by its name, and coupling the test to the implementation someAction
, one the other hand, when you change the algorithm of someAction
the test will be failed. you maybe add a test as displaysAnTitltedMenuItemInMenuWhenSomeActionIsCalledWithinATitle
.
As you can see the test will be coupling to the implementation in anyway. we only can do is make the test coupling to the implementation as lower as possible, so that, we just change a little tests when the implementation changed.
if you found the Menu
is an awkward one, you can use a MenuSpy
instead, and then write some IntegrationContractTest within MenuSpy
& MenuImpl
. as you can see that the Test using MenuSpy
is a little higher coupling to the implementation than a real Menu
, because we expects a titled Entry
was added in MenuSpy
not the effects of Menu
after a titled Entry
added.
let the MenuSpy
to checking whether a titled Entry
was added, for example:
someAction(title);
menuSpy->hasReceivedATitledEntry(title);
OR: you maybe checking a added Entry
whether is a CheckableEntry
in getAddedEntryTitle
method before title returned.
someAction(title);
EXPECT_TRUE(menuSpy->getAddedEntryTitle() == title);