5

The title is fairly self explanatory.

To elaborate: I'm currently updating a suite of unit tests for an application which makes heavy use of Entity Framework. We connect to this via a classic repository interface so it can be mocked out.

We're not doing test first (that's a whole different argument, which I don't want this question to degenerate into). Rather a "code a bit, test a bit" sort of approach. So we're not backfilling a whole application with tests, either.

I appreciate that a whole suite of tests for such an application is likely to require a very complex repository mock. However, I just created a new test class and the very first test required a mock repository with about 5 mocked out repository get/save functions.

It was a fairly simple function that was being tested. The range of mock classes were needed because of operations carried out in the class constructor and suchlike.

Having done so it struck me that that hardly looked like a unit. And that it might be a sign my code was too interdependent. So: is creating a single test that demands a complex mock often a sign of poor architecture?

  • A unit considered for testing can be quite big... Fowler talks about multiple classes as a single unit sometimes. – gbjbaanb May 14 '15 at 9:07
  • it possibly indicates a need to protect the code that you add with an anti-corruption layer. Whatever was written before is a matter of a technical-debt; the code that you add would better be easy to test – gnat May 14 '15 at 9:11
7

I'm going to have to make a couple of guesses here

You mention EF so I'm guess the mocks in question are related to the datalayer?

Since you are using EF, I guess your Repository presents an IQueryable and your Models construct queries within themselves?

This would lead to you then having to craft you mock with data which is consistent with the various queries your Models run, which I imagine could end up being pretty complicated.

I think the mistake here is the queryable repository. My view is that repositories should expose methods such as

IEnumerable GetModelsByConditionXAndConditionY(var valueOfAParmeter)

rather than

IEnumerable GetModelsByQuery(Func SomeQueryFunction)

or

IQueryable GetModelsButDontReturnThemYetINeedToThink()

This enables you to construct an in memory version of your database with consistent test data, because the ways in which that data are returned are known by the Repository.

Any Consuming class can take the repository and be expected to work correctly without model specific setup of the data.

I also tend to make this mock repository as its own class rather than using a mock framework to configure it per unit test

This makes your unit tests pretty simple as they all use the same mock data and allows you to inject the same mock repositories into your real app for UI testing etc

  • Interesting approach. Your assumptions are correct, but I've never seen this done before. Presumably because it would quickly make a very, very long list of repository methods. But I can see the advantages, as you've clearly explained. – Bob Tway May 14 '15 at 9:33
  • I don't seem to end up with too many, maybe 10-20 on big systems? I guess I do cheat a bit and use linq to trim/sort/join results where the returned data is more than required, but not so large as to cause slowdowns. ie. GetProductTypes vs GetProductTypesOrderedBy/InCategory/X/Y/Z – Ewan May 14 '15 at 9:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.