简体   繁体   中英

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?

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 (ie 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.

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();

Creating a mock of IEmailer and make it expect IEmailer.SendEmail()

is exactly the way you would test that.

since these are UNIT tests, you are not exposing too much. you are supposed to be exercising all the functions of the unit to be tested, and it's alright if you have internal knowledge of the unit.

I'm not very experienced with unit testing yet, so this might not be too helpful... but it seems to me your suggestion of mocking out the dependency is on the right track. You can then probe the state of the mocked dependencies after the operation completes, to determine whether or not the IEmailer performed the expected manipulations on them?

创建一个模拟IEmailer并期望调用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.

Then why are you exposing a public property requiring an internal interface?

Make the interface public and your implementations of them internal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM