Search code examples
phpphpunitclass-design

Writing mocks/stubs for an object before you have written the class for that object?


I'm designing a class that has two dependencies. One of the dependency classes has been written and tested. The other has not yet been written.

It has occurred to me because the remaining dependency will be written to facilitate the class that will use it, that I should write the latter first, and design the interface of the former as I go along, learning what it should do.

That seems to me to be a great way to make code. After all, as long as the main class gets a mock in its constructor, I can write it and test it without it being aware that its dependency doesn't exists, then I can create the dependency once I am sure I know what I need.

So: how do I do this? Create a skeleton class that I modify as I go along. Perhaps something like:

class NonExistantSkeleton
{
    public function requiredMethod1()
    {
    }

    public function newlyDiscoveredRequirement()
    {
    }
}

and then mock it using PHPUnit, and setting up stubs, etc, to keep my class under development happy?

Is this the way to go?

It seems like a nice way to develop code - and seems to me to make more sense than developing a dependency, without really knowing for sure how it's going to be used.


Solution

  • In short:

    Yes. At least thats what I'm doing right now.


    Longer Version:

    If the expected collaborators of your class don't exist at the point in time where you need them in your tests for the class you are building you have a few options:

    • Mock non existing classes (which phpunit can do)
    • Create class skeletions and mock those
    • Just create interfaces and get mocks for those (which phpunit can do too)
    • Maybe you don't need any of the above depending on the object

    If you programm against an interface anyways than all you need to do is to create that interface and tell PHPUnit to create a stub/mock from it

    • +No new class without a test
    • +Using interfaces when appropriate is considered nicer/better than just hinting against classes

    When mocking non existing classes you get some drawbacks that I don't like:

    • -High mock maintenance cost
    • -Chaning the methods on that classes is slow and tedious
    • -If you created the class you should rework the mocks again

    so I'd advice against that.

    The middle way would be to just create the empty class skeleton with its method and use those for mocking.

    I quite like that way in cases where there is no interface to hint against as It is fast and creates stable test code.

    Having barebone classes with public apis, for me, is no violation of TDD.


    There are classes you don't need to mock.

    Data transfer objects and Value Objects can always be created anywhere using the new in your production code so your tests also can just the the real objects.

    It helps to keep your tests a little cleaner as you don't need to mock/expect a lot of getter/setter methods and so on.