Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing class that does not have an output

Often times, a class would not have a direct output; it manipulates its dependencies, making them do things.

For example:

internal interface IEmailer
{
    void SendEmail();
}

class ReportSender
{
    public IEmailer Emailer { get; set; }

    public ReportSender(IEmailer emailerToUse)
    {
        Emailer = emailerToUse;
    }

    public void SendReport()
    {
        // Do whatever is needed to create the report

        Emailer.SendEmail();
    }
}

Creating a mock of IEmailer and make it expect IEmailer.SendEmail() seem to be exposing too much of the innards of the class and making the test fragile. But I can't think of any other way to test this class.

How should we write unit tests for such a class?

like image 514
rgunawan Avatar asked Mar 06 '26 01:03

rgunawan


2 Answers

Making a mock of IEmailer doesn't by itself expose too much of the class. Rather, it makes it open for extensibilty.

There's a certain tendendency that heavily relying on interaction-based testing (i.e. mocks) makes tests more fragile, but this is more of a design issue than an issue with mocks.

The Hollywood Principle can be really helpful here, because if your dependencies are mostly designed around void methods, dynamic mocks like Moq or Rhino Mocks will generally just ignore the method calls unless you specifically tell them to care about a particular one.

like image 66
Mark Seemann Avatar answered Mar 08 '26 14:03

Mark Seemann


Using Mock objects is the correct way to write the unit test for this method. You don't want your test to actually send an email. Mock objects let you break dependencies between different classes for the purposes of unit testing.

Here's an example using Rhino Mocks.

http://www.ayende.com/projects/rhino-mocks.aspx

IEmailer emailer = MockRepository.GenerateMock<IEmailer>();
emailer.Expect(x => x.SendEmail());

ReportSender reportSender = new ReportSender();
reportSender.Emailer = emailer;
reportSender.SendReport();

emailer.VerifyAllExpectations();
like image 40
jdot Avatar answered Mar 08 '26 14:03

jdot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!