Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection in NerdDinner - actually testing your repository or model

Consider a beginner dealing with Dependency Injection. We're analyzing two relevant classes in NerdDinner.

DinnerRepository from the application: Repo image

FakeDinnerRepository from the tests: Fakes image

They implement different logic, which of course is necessary, as the key idea here is to implement the IDinnerRepository, and provide different implementations and private members.

I understand the test is for the controller, but I am concerned that there are two different implementations of the data access logic. Consider any project that uses any kind of ORM, ADO.NET, SubSonic, or whatever flavour of data access you like. Yes, you can setup your fake repository to match the real repo.

My worry is that over time, implementation details in the real repo change. Perhaps a typo slips in, or some other important implementation detail changes in the query. This leads to a potential mismatch of the logic in the Model between the fake and the real repo. The worry is that the implementation of the real repo and test repo get out of sync.

Questions:

  • How would you test the Model in this case?
  • Is it appropriate to test the model?
  • Is it a matter of discipline to ensure your test keep up with the implementation of the business logic?
like image 991
p.campbell Avatar asked Oct 10 '09 15:10

p.campbell


2 Answers

This is probably not a complete answer to your question, but I'll try to get part of the way there.

The interface - in this case IDinnerRepository - should be seen as a contract. That means that any implementation has to fulfill this contract. If the method is FindAllDinners(), then that is basically what it should do. A fake repository used for unit tests can usually be a LOT simpler than the real thing (using a Dictionary for instance), so keeping up with the real implementation really shouldn't be seen as a problem, rather see it as a requirement.

The reason for the fake repository to exist in the first place is testing. Basically, everything that can be tested should be tested. And taking the database out of the equation is the point of an in-memory fake repository. The data access is not the point of the test, so we replace it. The fake repository is much faster to set up and use, and we can easily make sure the repo is in a state that it needs to be for the code under test to pass.

So what you do is to pass the model a copy of your fake repository in your unit tests, and make sure that whatever happens in the model code is reflected in the fake repository.

I think you'll find that in practice, it won't be a problem to keep the repositories in sync. If requirements change, you'll change the interface and both implementations will need to change. If the intentions change, you'll probably get to a point where your unit tests start to break.

Hope this helps!

like image 192
Rune Jacobsen Avatar answered Sep 27 '22 19:09

Rune Jacobsen


It's worth nothing that FakeDinnerRepository is to test code that requires an IDinnerRepository. Not to test DinnerRepository itself. If we used a real dinner repository to test things like the DinnerController we would not only be testing DinnerController's functionality, but also the data access itself. While the data access bits should certainly be tested, they should not be tested in the dinner controller's tests.

Testing your data access is a rather controversial topic. I believe the reason most people leave it out of their unit tests is simply that it takes much longer to execute. Having to query the database will add a ton of time to your testing that most developers would rather not endure.

Whether your data access gets tested in unit tests or more formal functional testing is up to you. But it certainly needs to be tested. Personally, I'm a fan of having transactional unit tests for the data access layer. Just make sure you're only testing your queries, and not testing that your ORM is working as it's supposed to (that's the ORMs job).

like image 28
Jim Mitchener Avatar answered Sep 27 '22 19:09

Jim Mitchener