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

2

8

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.

Apotheosize answered 18/1, 2012 at 9:24 Comment(0)
M
8

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.

Mouthpart answered 18/1, 2012 at 11:22 Comment(4)
Interfaces are a huge boost both for testing and substitutability in general, and I should have mentioned them in my answer so +1Subpoena
Thanks, that is perfect. I think perhaps extra time spent designing the classes, their collaborations and API, and then creating interfaces (which can be mocked against) seems a better way of doing things. What software do you use for designing classes? Is there anything you would recommend?Apotheosize
@LewisBassett Designing your classes is essentially an intellectual exercise, while there are CASE/UML tools out there that can help I'd say that the pen and paper has never been surpassed as a software design tool ;)Subpoena
@LewisBassett I do all my design in my IDE writing PHP code (or drawing on paper beforehand). IF you like UML you can do that too but I want my architecture executable/compilable and I'm not aware of any really full circle solid UML modeling tools for PHP. "EA" (Enterprise Architect something something money) is the best I've seen and that has a lot of shortcomings. ---Mouthpart
S
7

If you follow a development methodology then the usual approach is as follows:

  1. Figure out what your classes are meant to do, and what their public-facing APIs should be.
  2. Implement "empty" classes that consist of nothing but the public methods signitures with empty bodies (as you have done in the code example you gave).
  3. Work out an implementation strategy. This means working out which classes are dependant on each other and implementing them in an order that means that dependant classes aren't implemented until the classes it depends on are finished, or at least sufficiently functional to develop against. This means doing the classes with no dependencies first, then the classes that depend only on the completed classes, and so on.
  4. Write your tests. It's possible to write the tests now because you know what the black box for your classes look like, what they need to take as input and what they're supposed to return as output.
  5. Run the tests. You should get 0% success, but also 100% code coverage. This is now your baseline.
  6. Start to implement your classes according to your implementation strategy. Run your unit tests from time to time during this process, say once you've got a class completed, to make sure that it meets its specification as laid down in the unit test. Ideally, each test should show an increase in test passes whilst maintaining 100% code coverage.

EDIT: As edorian pointed out, PHP interfaces are a huge help here because PHPUnit can generate mocks and stubs from interfaces as well as from classes. They're also an excellent tool in reducing coupling and improving substitutability in general. They allow you to substitute any class that implements the expected interface, instead of just subclasses of the expected class.

Subpoena answered 18/1, 2012 at 10:57 Comment(1)
Thanks @Gordon. I agree with your processes - I have spent this morning writing tests and code for a class that depends on an object that doesn't yet exists, and its clear that this is not ideal. The only thing I disagree with is writing all the tests before writing code. According to Wikipedia (which is down now!) - test driven development is about writing one test, implementing code to make it pass, then writing another test, and implementing code to make that pass, etc. - en.wikipedia.org/wiki/Test-driven_developmentApotheosize

© 2022 - 2024 — McMap. All rights reserved.