2016-02-16 2 views
0

Как настроить отладку, чтобы вы могли пройти через вашу систему под тестовым кодом?Как настроить отладку для тестируемой системы при модульном тестировании?

Я получил этот тест:

[Test] 
    public void GetDeviceSettings_is_called() 
    { 
     //Arrange 
     var mockDeviceInteractions = new Mock<IDeviceInteractions>(); 
     mockDeviceInteractions.SetupSet(p => p._settingsFileQueue = It.IsAny<string>()); 
     mockDeviceInteractions.Setup(x => x.GetDeviceSettings(It.IsAny<string>(), It.IsAny<string>())); 
     //Act 
     mockDeviceInteractions.Object._settingsFileQueue = @"C:\"; 
     mockDeviceInteractions.Object.GetDeviceSettings("123123", "dfgdfg"); 
     //Assert 
     mockDeviceInteractions.VerifyAll(); 
    } 

и вот метод, который я веду себя по:

public virtual DeviceSettings GetDeviceSettingsForSerialNumber(string serial) { 

//do stuff - and i've put a break point here, but it does not step at the break point 
GetDeviceSettings(string1, string2); 
//do more stuff 
    } 

Что я делаю неправильно? Почему он не останавливается на точке останова?

+4

Это не останавливается, потому что ** вы не используете класс 'DeviceInteractions' ** - вы используете его издеваемую версию. – stuartd

+0

, но в этом случае я не смог бы использовать какие-либо функции moq, такие как setup и verifyall right? –

+0

Вы могли бы использовать эти функции, так как вы создали Mock и высмеивали 'GetDeviceSettingsForSerialNumber' как этот' virtual'. В фоновом режиме «Moq» создает переопределенный метод для вас, который вы вызываете, который ничего не делает. Плюс 'VerifyAll' ничего не проверит, поскольку вы не настроили проверку. –

ответ

1

чтобы ответить на этот вопрос,

Как установить отладку, так что вы можете пошагово ваша система под тестовым кодом?

Нет никакой конкретной настройки, которую вы должны сделать, это будет отличаться от отладки системы, запущенной из кнопки Start в Visual Studio.

Единичный тест - это просто код, который подчеркивает public API class. Единственное различие между модульным тестом и фактическим вызовом публичного API - это то, что у вас есть attributes, чтобы добавить к этому методу и что вы зависимы от mock внутри класса. Сам класс остается таким же, как при обычной отладке, но у вас есть сценарии настройки, чтобы он обрабатывал разные логические схемы, которые затем можно было бы сделать verify.

Чтобы получить тест бегун, чтобы запустить тест в debug вы должны выбрать его для запуска в debug иначе большинство бегунов по умолчанию работает в том, что в основном release режим. В зависимости от бегуна, который вы используете, это выполняется по-другому, но чаще всего вы можете провести тест debug и выбрать что-то вдоль линий Debug the selected Tests.

Обращаясь к следующему вопросу,

Что я делаю неправильно? Почему он не останавливается на точке останова?

Когда вы выполняете единичный тест, как описано выше, вы тестируете фактический класс, но настраиваете сценарии, которые логическая реализация должна обрабатывать правильно.

Основная проблема заключается в том, что вы не выглядите так, как будто вы когда-либо называете метод, который вы ожидаете запустить, тест никогда не вызывает GetDeviceSettingsForSerialNumber(...), если это не вызвано настройкой свойства, которое вы не описали.

Что вы на самом деле сделали, это издеваться над тестируемой системой, поэтому на самом деле не тестирует реализованный код, но в основном тестирует, что moq работает правильно. Это можно определить по этой линии:

mockDeviceInteractions.Setup(x => x.GetDeviceSettings(It.IsAny<string>(), It.IsAny<string>())); 

Вы насмешливый вызов GetDeviceSettings(string, string), я не уверен, что на реализацию этого метода, но если метод помечен как virtualmoq будет в фоновом режиме создания нового переопределенный метод, который будет вызываться, когда любой аргументstring.

Вы тогда телефону:

mockDeviceInteractions.Object.GetDeviceSettings("123123", "dfgdfg"); 

moq в фоновом режиме принимает этот вызов и перехватчик сопрягает это один из вызовов установки (смотри выше), это будет вызывать вызов настройки не который ни ничего не делает и ничего не возвращает.

Если метод, который вы пытаетесь проверить «GetDeviceSettingsForSerialNumber» вызывается, когда свойство (я надеюсь, что это не поле вы звоните) установлено это обнуляется при настройке свойства с вызовом:

mockDeviceInteractions.SetupSet(p => p._settingsFileQueue = It.IsAny<string>()); 

Я никогда не пытался этого, но я не верю, что он запустит фактический набор свойств в классе, который может быть тем, что вы ищете.

Если вы хотите настроить свойство иметь значение по умолчанию, вы в состоянии сказать:

mock.SetupProperty(f => f.Name, "foo"); 

Теперь я мог бы объяснить, почему я чувствую, что вы тестируете неверен, но я чувствую, что @stuartd ответ описывает, как class должен быть структурирован в зависимости от зависимостей, которые вы можете высмеивать, чтобы возвращать данные вместо издевательских вызовов в тестируемой системе. Вместо этого я покажу вам, как я смогу структурировать ваш фактический тест со структурой, которая у вас есть сейчас.

[Test] 
public void GetDeviceSettings_is_called() 
{ 
    //Arrange 
    var mockDeviceInteractions = new Mock<IDeviceInteractions>(); 
    var deviceSettings = new Mock<IDeviceSettings>(); 
    mockDeviceInteractions.Setup(x => x.GetDeviceSettings(@"123123", "dfgdfg")) 
     .Returns(deviceSettings.Object) 
     .Verifiable(); 

    //Act 
    var actual = mockDeviceInteractions.Object.GetDeviceSettingsForSerialNumber(@"123123"); 

    //Assert 
    Assert.Equal(deviceSettings.Object, actual); 
    mockDeviceInteractions.Verify(); 
} 

Во-первых я удалил вас SetupSet на имущество, это не требуется, если вы хотите, чтобы установить фактическое свойство просто установить его на объект, я также удалил свойство задается как я не мог посмотрите, как это соответствует вашему тесту, если вы не ожидаете, что этот метод будет вызван из средства настройки свойств, которое вы не описали.

Далее я добавил Returns вызов метода в к вашему Setup из GetDeviceSettings, я не был уверен, что это возвращается, но как вы можете видеть, что это возвращает в моем примере с IDeviceSettings и я также отметил это как Verifiable.

Я тогда называю фактическим GetDeviceSettingsForSerialNumber от вас. Вы никогда не называли это вообще, поэтому я не удивлен, что вы не смогли попасть в точку останова.

Наконец, я утверждаю, что возвращенный из вызова IDeviceSettings тот же, что и метод GetDeviceSettings. Я знаю, что это немного отличается от вашей реализации, поскольку вы возвращаете конкретный DeviceSettings, но это должно фактически вернуть interface.

Наконец я проверки mockDeviceInteractions, как вы можете видеть, с Verify вызовом, а не VerifyAll вызова, как я иногда установки макета с вызовами, которые я делаю, не нужное хотение Verify и только те марка, которые я хочу до Verify с правильным вызовом метода.

+0

Спасибо Стивен ... Я видел свет –

+0

Не могли бы вы объяснить, что это делает: Assert.Equal (deviceSettings.Object, actual); –

+0

'Assert.Equal (object, object)' проверяет, что фактический объект совпадает с ожидаемым объектом. Поэтому его можно использовать как 'Assert.Equal (3, Add (1, 2))', я ожидаю, что результат будет равен 3, а фактический результат будет результатом вызова 'Add (1, 2)' , Поскольку мы все знаем, что если вы добавите 1 и 2, вы ожидаете, что результат будет равен 3. Это также можно использовать с объектами, чтобы убедиться, что они одинаковы, что я использовал в этом примере. –

2

Вы должны издеваться объектов, которые будут вызываться по классу испытуемых, а не сам класса.

Вот пример. Предполагается, что вы можете вводить зависимости в свои классы.

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

public enum ReactorStatus { Ok, OhDear}; 

public interface IReactorInteractions { 
    ReactorStatus ShutDown(bool nicely); 
    ReactorStatus Status { get; } 
} 

public interface ICore { 
    ReactorStatus ShutDown(bool nicely); 
    ReactorStatus GetStatus(); 
} 

public class ReactorInteractions : IReactorInteractions { 

    private ICore reactor; 
    public ReactorInteractions(ICore reactor) { 
     this.reactor = reactor; 
    } 

    public ReactorStatus ShutDown(bool nicely) { 
      return reactor.ShutDown(nicely); 
    } 

    public ReactorStatus Status { 
    get { return reactor.GetStatus(); } 
    } 
} 

Итак, вы хотите протестировать класс ReactorInteractions.

Для этого вы издеваетесь над объектом, который он называет, в данном случае ICore. Вы не хотите выполнять операции с фактическим ядром. Это, безусловно, будет дисциплинарным преступлением, по крайней мере!

Вы должны пройти Object свойства ICore издеваться в качестве параметра конструктора класса ReactorInteractions - это свойство не то, что вы должны получать доступ в тесте, он предназначен исключительно для передачи в класс при испытании - именно этот «объект», что класс испытываемого действует на, что позволяет использовать Setup и Verify:

private Mock<ICore> mockCore; 
private IReactorInteractions reactor; 

[SetUp] 
public void TestSetup() { 
    mockCore = new Mock<ICore>(); 
    reactor = new ReactorInteractions(mockCore.Object); 
} 

Так некоторые примеры тестов (которые, если бы они были реальные испытания будут проверки и проверок заслуживающих вещей - тесты должны проверка логика, нет водопровод.):

[Test] 
public void ShutDown_Nicely_Should_Pass() { 
    mockCore.Setup(m => m.ShutDown(true).Returns(ReactorStatus.Ok)); 
    var status = reactor.ShutDown(true); 
    status.Should().Be(ReactorStatus.Ok); 
    mockCore.VerifyAll(); 
} 

[Test] 
public void ShutDown_Badly_Should_Fail() { 
    mockCore.Setup(m => m.ShutDown(false).Returns(ReactorStatus.OhDear)); 
    var status = reactor.ShutDown(false); 
    status.Should().Be(ReactorStatus.OhDear); 
    mockCore.VerifyAll(); 
} 

Обратите внимание, что я не использую It.IsAny<bool> в моей тестовой настройке. Этот синтаксис неверен для разработчиков, новых для насмешек (замечено в дикой природе: попытка использовать It.IsAny в качестве параметров в тестовых вызовах) - это то, что я хочу, чтобы автор Moq выделил в документации. It.IsAny должен использоваться только в том случае, если у вас нет абсолютно никакого контроля над параметром.

В вашем случае нет необходимости использовать It.IsAny - вы точно знаете, какие ценности вы собираетесь пройти:

const string serial = "123456"; 
mockDeviceInteractions.Setup(m => m.GetDeviceSettingsForSerialNumber(string serial)) 
         .Returns(new DeviceSettings { Serial = serial }; 

var settings = classUnderTest.GetDeviceSettingsForSerialNumber(serial); 
settings.Serial.Should.Be(serial); 

Тогда в тесте, вы проверяете, что фактического значения используется.Если вы проверите для It.IsAny, то имейте в виду, что часть вашего кода, которая имеет дело с этим значением, может быть заменена генератором случайных чисел, и модульный тест все равно пройдет.

Сказав это, у Moq было ограничение, что если один аргумент в списке неизвестен и должен использовать It.IsAny, тогда все они должны быть (я больше его не использую, поэтому я не знаю, случай, но я помню, вы могли бы работать вокруг, что в любом случае, используя функцию обратного вызова для проверки параметров вручную)

+0

Узнал тон от этого поста. Большое спасибо –

Смежные вопросы