开发者

Unit testing help

Given the the following method what and how can I test?

p开发者_StackOverflow中文版ublic void DoSomething
{
   Get Db record 
   Update Db the record
   Log History in Db
   Send an email notification
}


First of all, I agree with the other posters that this method is doing too much. I personally would have it do only the Db stuff, then have my application layer log the action and send the email. That said, to unit test this method, I would do the following (in C#):

Firstly, give the class that method exists in a constructor like this:

public MyClass(
    IRepository repository,
    ILoggingService loggingService,
    INotificationClient notificationClient)

...where the IRepository is an interface something like this:

interface IRepository
{
    Db GetDbRecord();
    void UpdateDbRecord(Db record);
}

...the ILoggingService is something like this:

interface ILoggingService
{
   void LogInformation(string information);
}

...and the INotificationClient is something like this:

interface INotificationClient
{
    void SendNotification(Db record);
}

In the constructor body, assign the passed-in parameters to private, readonly fields in MyClass.

Next, in the DoSomething method, get the Db record from the IRepository, update it and save it back to the IRepository. Log the history using the ILoggingService, then call SendNotification() on the INotificationClient.

Finally, in your unit tests, use a mocking framework (like Moq) to mock up one of each of the interfaces. Pass the mocked objects into a new instance of MyClass, call DoSomething(), then verify that your mocked IRepository has been asked to update the Db object, your mocked ILoggingService has been asked to log a message, and your mocked INotificationClient has been asked to SendNotification(). That is to say:

Db record = new Db();

var mockRepository = new Mock<IRepository>();
mockRepository.Setup(r => r.GetDbRecord()).Returns(record);

var mockLoggingService = new Mock<ILoggingService>();

var mockNotificationClient = new Mock<INotificationClient>();

new MyClass(
    mockRepository.Object,
    mockLoggingService.Object,
    mockNotificationClient.Object).DoSomething();

// NUnit syntax:
Assert.That(record["ExpectedUpdatedField"], Is.EqualTo("ExpectedUpdatedValue"));

mockRepository.Verify(r => r.UpdateDbRecord(record), Times.Exactly(1));

mockLoggingService.Verify(ls => ls.LogInformation(It.IsAny<string>()), Times.Exactly(1));

mockNotificationClient.Verify(nc => nc.SendNotification(record), Time.Exactly(1));

In the running system you would inject proper implementations of MyClass' dependencies, and you've then shared the responsibilities amongst more coherent objects.

Bit long-winded, but that's how I'd do it :)


For Unit testing - you are not having a "unit" method. It is doing too many things. Extract out methods for each single job it does and test those methods.

Generally, Unit Tests do not include DB changes etc. so you have to see how you can attack that part. It is going to depend on the framework you use etc. You can mock the database methods and verify you are calling them. Don't go about seeing if the data is added to db etc. That is not Unit testing and you will start to realize that your tests become flaky, slow and cannot be parallelized etc.

Have integration tests / db test for the data part and make sure you rollback any data that you modify. Also make sure that no test is dependent on a change made by some other test.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜