Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unit testing & constructor dependency injection

I have an issue regarding how one would go about designing an application suited for unit-testing.

I am trying to implement the SRP (Single-Responsibility Principle), and from what I understood this involves splitting out most functionality in seperate, dedicated classes to keep code more organised. For example, I have this specific scenario.

A class RecurringProfile, which has a method .ActivateProfile(). What this method does is mark the status as activated, and create the next (first) recurring payment for the next due date. I was going to split out the functionality to create the next recurring payment in a seperate class, for example RecurringProfileNextPaymentCreator. My instant idea is to have this class take the 'RecurringProfile' as a parameter in it's constructor:

RecurringProfileNextPaymentCreator(IRecurringProfile profile)

However, I think this would be problematic for unit-testing. I would like to create a unit-test which tests out the ActivateProfile functionality. This method would get an instance of an IRecurringProfileNextPaymentCreator via dependency injection (Ninject), and call the method .CreateNextPayment.

My idea to create a unit-test was to create a mock of an IRecurringProfileNextPaymentCreator, and substitue that so that I can verify that the .ActivateProfile() actually called the method. However, due to the constructor parameter, this would not fit as a default constructor for NInject. Having to create a custom NInject provider just for such a case (where I can have many such classes all over the solution) would be a bit overkill.

Any ideas / best practices how one would go about this?

-- Below is a sample code regarding the above example: (Please note that the code is hand-written, and is not syntactically 100% correct)

public class RecurringProfile
{
    public void ActivateProfile()
    {
        this.Status = Enums.ProfileStatus.Activated;
        //now it should create the first recurring payment
        IRecurringProfileNextPaymentCreator creator = NInject.Get<IRecurringProfileNextPaymentCreator>();
        creator.CreateNextPayment(this); //this is what I'm having an issue about 
    }
}

And a sample unit-test:

public void TestActivateProfile()
{   
    var mockPaymentCreator = new Mock<IRecurringProfileNextPaymentCreator>();
    NInject.Bind<IRecurringProfileNextPaymentCreator>(mockPaymentCreator.Object);

    RecurringProfile profile = new RecurringProfile();
    profile.ActivateProfile();
    Assert.That(profile.Status == Enums.ProfileStatus.Activated);
    mockPayment.Verify(x => x.CreateNextPayment(), Times.Once());

}

Going up to the sample code, my issue is whether it is a good practice to pass over the RecurringProfile as a parameter to the creator.CreateNextPayment() method, or whether it makes more sense to somehow pass the RecurringProfile to the DI-framework, when getting an instance of an IRecurringProfileNextPaymentCreator, considering that the IRecurringProfileNextPaymentCreator will always act on an IRecurringProfile to create the next payment. Hope this makes the question a bit more clear.

like image 807
Karl Cassar Avatar asked Oct 15 '12 13:10

Karl Cassar


People also ask

What is unit testing with example?

Unit testing is testing the smallest testable unit of an application. It is done during the coding phase by the developers. To perform unit testing, a developer writes a piece of code (unit tests) to verify the code to be tested (unit) is correct.

What is unit testing and its types?

Unit Testing is defined as a type of software testing where individual components of a software are tested. Unit Testing of the software product is carried out during the development of an application. An individual component may be either an individual function or a procedure.

How unit testing is performed?

A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.

Why unit testing is used?

One of the benefits of unit tests is that they isolate a function, class or method and only test that piece of code. Higher quality individual components create overall system resiliency. Thus, the result is reliable code. Unit tests also change the nature of the debugging process.


1 Answers

You shouldn't be using your DI container(Ninject) during such unit-tests. You would manually inject the mock object when newing up the class under test. Then verify the call was made on the mock.

like image 148
Kelly Ethridge Avatar answered Oct 31 '22 11:10

Kelly Ethridge