Как выполнить модульное тестирование метода, который ожидает обновления объекта по ссылке?
У меня проблемы с модульным тестированием метода, который изменяет некоторые свойства ссылочного типа, который передается ему.
В качестве примера, скажем, у меня есть класс с именем Policy.
Policy policy = new Policy();
policy.Status = Active;
Затем я передаю эту политику менеджеру политики, чтобы ее деактивировать.
policyManager.InactivatePolicy(policy);
Метод политики инактивации выполняет следующие действия:
public void InactivatePolicy(Policy policy)
{
policy.Status = Inactive;
UpdatePolicy(policy); //saves the updated policy details via nhibernate
}
У меня проблемы с модульным тестированием этого метода DoSomething. (игнорируйте тот факт, что то, что он делает в этом примере, бесполезно)
public void DoSomething(Policy policy)
{
Policy policy = new Policy();
policy.Status = Active;
policyManager.InactivatePolicy(policy);
}
Поскольку я делаю макет диспетчера политик, статус не устанавливается неактивным, и в результате, когда я утверждаю, что после вызова DoSomething статус политики неактивен, я получаю тестовый сбой, поскольку он все еще активен.
[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
MyClass mc = new MyClass(policyManagerMock.Object);
Policy policy = new Policy();
policy.Status = Active;
mc.DoSomething(policy);
Assert.That(policy.Status, Is.EqualTo(Inactive)); //this fails
}
Так что я нахожусь в ситуации, когда код работает на самом деле, но не в изоляции в моих модульных тестах.
Единственный способ обойти эту проблему - заставить метод InactivatePolicy менеджера политики вернуть измененную политику, чтобы я мог смоделировать ожидаемое возвращаемое значение.
public Policy InactivatePolicy(Policy policy)
{
policy.Status = Inactive;
UpdatePolicy(policy); //saves the updated policy details via nhibernate
return policy;
}
[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
MyClass mc = new MyClass(policyManagerMock.Object);
Policy expectedInactivePolicy = new Policy();
expectedInactivePolicy.Status = Inactive;
Policy policy = new Policy();
policy.Status = Active;
policyManagerMock
.Setup(p => p.InactivatePolicy(policy))
.Returns(expectedInactivePolicy);
mc.DoSomething(policy);
Assert.That(policy.Status, Is.EqualTo(Inactive)); //this now succeeds
}
Обычно, когда я пытаюсь что-то тестировать, это говорит о том, что я делаю что-то не так.
Кто-нибудь знает, есть ли лучший способ сделать это? Нужно ли по существу возвращать значения, которые изначально предназначались для обновления с помощью ссылочного значения, которое было передано в метод?
Возможно, моя проблема в том, что у менеджера политики не должно быть метода InactivatePolicy, но вместо этого он должен быть на самом объекте Policy, а обновление базы данных вызываться позже?
3 ответа
Вы не должны издеваться над PolicyManager, вы должны издеваться над методом UpdatePolicy, поскольку вы все еще хотите проверить функциональность метода DoSomething.
Кроме того, вы, вероятно, тестируете слишком высоко дерево.
Вы должны протестировать метод InactivatePolicy() изолированно и проверить только то, что функциональность работает, а затем вы должны протестировать метод DoSomething(), снова в Isolation.
Здесь у вас есть 2 отдельных блока кода, и у вас должны быть модульные тесты, которые тестируют каждый блок отдельно.
Я думаю, что этот тест неправильный, потому что на самом деле вы тестируете фиктивный объект и его влияние на активное состояние вашего объекта политики, а не тестируете исходный объект, и даже если тест проходит в реальном сценарии, PolicyManager может вести себя по-другому и вызывать сбой DoSomething. Возможно, вам лучше протестировать PolicyManager и его метод UpdateInactive в модульном тесте и провести тест на целостность, чтобы протестировать DoSomething вместе с реальным PolicyManager.
бессвязный
Я не совсем понимаю.
Если вы не проверяете тот факт, что он настроен на true
через NHibernate (то есть вы предполагаете, что это работает), тогда что вы вообще тестируете? Зачем вообще проверять, что значение установлено, учитывая, что в рабочем коде вы просто предполагаете, что это так? Даже если бы вы тривиально копировали систему, которая устанавливает ее в true, я не вижу в этом смысла, потому что это не то же самое, что рабочий код.
В лучшем случае я бы подумал о том, чтобы иметь "издевательское" хранилище данных; не nHibernate, это просто ничего не делает. В этом случае это будет реализовано в UpdatePolicy
класс, с некоторым 'MockRepo' вместо 'nHibernateRepo'.
Таким образом, если вы настроите репо надлежащим образом, вы увидите, что он установлен.
Хотя я бы удивился, потому что, возможно, в вашем коде nHibernate есть ошибка, и фактически все, что вы проверяете, это установка логического значения.
Резюме
Почему бы просто не создать тестовую базу данных, с которой вы можете запустить этот тест?