0

My question is similar to this one: Should I mock all the dependencies when unit testing?

I understand the benefit of mocking when my code accesses a database or a web service or a file on the file system. Mocking means that if there is an issue that I have no control over e.g. a network issue, then my unit tests will pass - because my code is still correct.

However, say I have some code like this:

public Offer AssignOffer(OfferType offerType, IOfferValueCalculator valueCalculator) 
        { 
            DateTime dateExpiring = offerType.CalculateExpirationDate(); 
            int value = valueCalculator.CalculateValue(this, offerType); 


            var offer = new Offer(this, offerType, dateExpiring, value); 


            _assignedOffers.Add(offer); 


            NumberOfActiveOffers++; 


            return offer; 
        } 

which I took from here: https://github.com/jbogard/presentations/blob/master/WickedDomainModels/After/Model/Member.cs

Is it normal practice to mock the object parameters passed to the method i.e. OfferType and IOfferValueCalculator (interfaces and classes I have written)? These classes were written by me and are in the same project as Member.AssignOffer.

I asked a similar question earlier; however it was closed because opinion based. I have tried to make this question more clearer by providing example code.

My question is also similar to this: When should I mock?.

This: https://lostechies.com/jimmybogard/2011/01/07/putting-mocks-in-their-place/ and this: http://www.taimila.com/blog/ddd-and-testing-strategy/ seem to advise only mocking: "Mock across architecturally significant boundaries, but not within those boundaries".

w0051977
  • 15,099
  • 32
  • 152
  • 329
  • I suspect it's still pretty opinion-based, but still of value perhaps. The question really becomes, "What is this test validating?" If you *don't* mock the inputs then the test is *also* validating the objects being supplied, at least to some degree. Those objects could in some way fail, which would cause this test to fail even though the specific method being tested *did not* fail. (A dependency did.) If this is acceptable, then you don't need to mock. If, however, you want a more purist approach to *only* test this method, mocking is advised. – David Jan 24 '18 at 16:53
  • The nature of answer you're seeking is opinion based. There's no silver bullet for mocking. When people talk about unit testing they imply unit is a class, but is your unit really a single class? A unit can easily be a tree of classes where only the aggregate root matters. Why mock it's components if they have no purpose without the parent? – Justinas Marozas Jan 24 '18 at 16:56
  • @Justinas Marozas, I agree. Could you tailor your comment/answer to the code in my question? i.e. would you mock OfferType and IOfferValueCalculator? – w0051977 Jan 24 '18 at 16:59

2 Answers2

0

Yes, if you mock offer type, IOffervalueCalculator you can test other part of code with different combinations of offer type, expiration date etc..

JyothiJ
  • 315
  • 1
  • 11
  • I was reading this: https://lostechies.com/jimmybogard/2011/01/07/putting-mocks-in-their-place/ and this: http://www.taimila.com/blog/ddd-and-testing-strategy/, which conclude: "Mock across architecturally significant boundaries, but not within those boundaries". Therefore I don't think I agree with you. – w0051977 Jan 24 '18 at 17:18
0

TL;DR: No, it's definitely not necessary to mock every injected type.

In general you would mock objects outside of context of your unit. It's easy to know to mock file system, databases, etc., because boundaries between your application and those external components are very clear.

Inside your application however it's not black and white. If your components are well defined and have clear boundaries, choosing what to mock can be easy. If those boundaries aren't well defined it will be hard to choose what needs mocking and in this case I'd recommend mocking eagerly. Poorly defined context boundaries usually lead to many dependencies and not mocking that can lead in brittle tests.

In the code example you chose in your question, after briefly looking at the repo, I'd mock both OfferType and IOfferValueCalculator. I'll be using power of names to expand why:

  • Class to test is Member. No clue in what context that belongs;
    • This signals unclear boundaries of context - best to treat dependencies as external if unsure;
  • Main task of the method is to "assign offer". Do I care what expiration date an external component will calculate as long as I know method used it as intended? No;
    • Side question: Why method assigning offer even deals with calculations of expiration date? How is that single responsibility?
  • Would I think IOfferValueCalculator belongs in the same context as Member I'd probably not mock it. But again - I don't think so and in the context of "assign offer" problem calculated value is not an important detail;

In summary: With different names to object and method in test better knowledge of application my answer might be different. Now it's hard to reason what belongs where and what should depend on what.

In a different scenario, where I'd see a concise cluster of tightly related types with few dependencies to other clusters I'd be much less eager to mock.

Justinas Marozas
  • 2,482
  • 1
  • 17
  • 37
  • OfferType, Member and ValueCalculator are part of the same aggregate. On that basis they are a logical grouping of classes? Therefore I am airing on the side that mocks are not needed. What do you think? – w0051977 Jan 24 '18 at 19:08
  • If that's the case I'd say you don't need to mock them. You might still need to mock their dependencies if they cross the boundaries of that logical grouping. Don't take it for a hard rule of sorts though. There will always be exceptions. – Justinas Marozas Jan 25 '18 at 00:06