0

I am trying to write a couple of classes using SOLID principles and having some trouble.

The problem is quite simple. I have an application that tracks leads. Leads are created when events are raised by the customer - eg file download, registration, page view, etc. A lead can have multiple opportunities - ie opportunities are for different products.

  1. A lead should be created if it doesn't exist.
  2. An opportunity should be created for that lead if it does not exist
  3. The lead score should be incremented based on some event scoring table

The way I wanted to do it was to have a LeadEventHandler class that calls three services TrackLead, TrackOpportunity and IncrementLeadScore. This seems ok, but testing the LeadEventHandler required me to use any-instance which is a code smell.

Note I know I could test the whole chain in LeadEventHandler, but for learning's sake I wanted to test in isolation. I could have injected the dependencies into LeadEventHandler, but this just didn't seem correct.

It would be great if I can let the tests drive my code, but I seem to run into quite a few stumbling blocks.

2
  • 1
    "Design Question" is a very generic title–it describes any question that could be asked on Programmers.SE.
    – outis
    Nov 3, 2014 at 9:07
  • Discussion on the implications of using private methods in a TDD scenario: c2.com/cgi/wiki?TestingPrivateMethodsInCeePlusPlus
    – pup
    Nov 11, 2014 at 21:18

1 Answer 1

1

Speaking purely solid your classes:

TrackLead, TrackOpportunity 

Are already fine grained and therefore should be compliant to 'S' single responsibility.

Your class:

LeadEventHandler 

Your lead event handler is like a controller to all these smaller processes, so for it to take in dependencies to the TrackLead and Trackopportunity classes makes it compliant to DI but not necessarily 'O' as it is not easily open to extension. To make this easier make sure that your Lead events are stored inside a list in LeadEventHandler that will be enumerated each time an event is received. This way event processors can be added at run time or from an external config. Making it 'O' compliant without changing the code of LeadEventHandler

As far as unit testing is concerned, instances of TrackLead and TrackOpportunity should be mocks/stubs when testing LeadEventHandler because you should not actually be testing their functionality but only that their entry point methods was called

PS: The system you are describing is a very good fit for event based/message bus pattern. Perhaps you can implement something similar

2
  • Thanks for the answer. Regarding the instances of TrackLead, TrackOpportunity - how would you stub them out if they are hidden in the implementation of the LeadEventHandler. The only way I know that can be done is to make the public or inject them as dependencies into the class. If you look at the any-instance link it's considered a code smell if you stop our all instances of a class. That is the main part I am confused with. Nov 3, 2014 at 11:12
  • 1
    The assumption here is that Tracklead and TrackOpportunity are seperate objects and therefore can be dependency injected. Therefore you can inject a mock already and dont need to use the any instance feature.
    – Andre
    Nov 3, 2014 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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