Помощь в модульном тестировании - PullRequest
1 голос
/ 21 мая 2011

Учитывая следующий метод, что и как я могу проверить?

public void DoSomething
{
   Get Db record 
   Update Db the record
   Log History in Db
   Send an email notification
}

Ответы [ 2 ]

1 голос
/ 21 мая 2011

Прежде всего, я согласен с другими авторами, что этот метод делает слишком много. Лично я хотел бы, чтобы он выполнял только Db, затем мой прикладной уровень регистрировал действие и отправлял электронную почту. Тем не менее, для модульного тестирования этого метода я бы сделал следующее (в C #):

Во-первых, передайте классу, что метод существует в конструкторе, например:

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

... где IRepository - это интерфейс, подобный следующему:

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

... ILoggingService выглядит примерно так:

interface ILoggingService
{
   void LogInformation(string information);
}

... и INotificationClient выглядит примерно так:

interface INotificationClient
{
    void SendNotification(Db record);
}

В теле конструктора присвойте переданные параметры частным полям, доступным только для чтения, в MyClass.

Затем, в методе DoSomething, получите запись Db из IRepository, обновите ее и сохраните обратно в IRepository. Записать историю, используя ILoggingService, затем вызвать SendNotification() на INotificationClient.

Наконец, в ваших модульных тестах используйте макет (например, Moq) для макетирования одного из каждого интерфейса. Передайте смоделированные объекты в новый экземпляр MyClass, позвоните DoSomething(), затем убедитесь, что ваш смоделированный IRepository получил запрос на обновление объекта Db, ваш смоделированный ILoggingService попросил записать сообщение, а твою издевательскую INotificationClient попросили SendNotification(). То есть:

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

В работающей системе вы вводите правильные реализации зависимостей MyClass ', и затем вы распределяете обязанности между более связными объектами.

Немного скучно, но вот как я это сделаю:)

0 голосов
/ 21 мая 2011

Для юнит-тестирования - у вас нет метода "юнит".Он делает слишком много вещей.Извлеките методы для каждой отдельной работы и протестируйте эти методы.

Как правило, модульные тесты не включают изменения БД и т. Д., Поэтому вы должны увидеть, как можно атаковать эту часть.Это будет зависеть от используемой вами среды и т. Д. Вы можете смоделировать методы базы данных и убедиться, что вы их вызываете.Не смотрите, будут ли данные добавлены в БД и т. Д. Это не модульное тестирование, и вы начнете понимать, что ваши тесты становятся нестабильными, медленными и не могут быть распараллелены и т. Д.

Есть интеграционные тесты / дБпроверьте часть данных и убедитесь, что вы откатили все данные, которые вы изменили.Также убедитесь, что ни один тест не зависит от изменений, сделанных другим тестом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...