Есть ли веская причина использовать DI с модулем / классом без зависимостей в модульном тесте?
Инъекция зависимостей может оказаться очень полезной для тестирования модулей с зависимостями. Дело не в них.
Скажем, что есть какая-то конкретная реализация,
public class DoesSomething : IDoesSomething
{
public int DoesImportant(int x, int y)
{
// perform some operation
}
}
, который реализует это,
public interface IDoesSomething
{
int DoesImportant(int x, int y);
}
В модульном тесте вы, очевидно, можете new
поднять тест,
[TestMethod]
public void DoesSomething_CanDoDoesImportant()
{
int expected = 42;
IDoesSomething foo = new DoesSomething();
int actual = foo.DoesImportant(21, 2);
Assert.AreEqual(expected, actual);
}
Или использовать DI (Autofac здесь, но не должно иметь значения для принципа вопроса),
[TestMethod]
public void DoesSomething_CanDoDoesImportant()
{
var builder = new ContainerBuilder();
builder.RegisterType<DoesSomething>().As<IDoesSomething>();
var container = builder.Build();
int expected = 42;
IDoesSomething foo = container.Resolve<IDoesSomething>();
int actual = foo.DoesImportant(21, 2);
Assert.AreEqual(expected, actual);
}
Учитывая такой автономный модуль без зависимостей, есть ли веская причина для введения IDoesSomething
в тест? Или есть ли убедительная причина не вводить IDoesSomething
?
2 ответа:
Нет необходимости использовать контейнер DI для этого теста.
Вот причина, по которой Вы могли бы использовать DI container для разрешения конкретного класса: все другие тесты используют аналогичный шаблон для построения типа через контейнер, и этот просто не требует зависимостей.
Пример единства:
Побочное преимущество этого подхода состоит в том, что ваш тест нуждается в минимальных изменениях, когда[TestMethod] public void DoesSomething_behaves_correctly() { var expected = 42; var container = new UnityContainer(); var foo = container.Resolve<DoesSomething>(); int actual = foo.DoesImportant(21, 21); Assert.AreEqual(expected, actual); }
DoesSomething
начинают иметь зависимости.
Ваши тесты должны быть написаны специально для конкретной реализации .
Возьмем для примера:
public void DoTestA() { ObjectFactory.Set<IDoesSomething, DoesSomethingBadly>(); var doesSomething = ObjectFactory.Get<IDoesSomething>(); Assert.AreEqual(0, doesSomething.Add(1,1)); } public void DoTestB() { int expected = 42; //This test is now *completely* dependent on DoTestA, and can give different results //depending on which test is run first. Further, we don't know //which implementation we're testing here. It's not immediately clear, even if //there's only one implementation. //As its a test, it should be very explicit in what it's testing. IDoesSomething foo = ObjectFactory.Get<IDoesSomething>(); int actual = foo.DoesImportant(21, 21); Assert.AreEqual(expected, actual); } // Define other methods and classes here public class DoesSomething : IDoesSomething { public int Add(int x, int y) { return x+y; } } public class DoesSomethingBadly : IDoesSomething { public int Add(int x, int y) { return x-y; } } public interface IDoesSomething { int Add(int x, int y); }
В тестах прямая ссылка на класс-это, безусловно, правильный путь. Нас не волнует, что это интерфейс, нас волнует только конкретная реализация.
var foo = new DoesSomething();
это определенно лучший вариант.
IDoesSomething foo = new DoesSomething();
это не вредно, но кажется совершенно ненужным, так как, опять же, мы заботимся только о реализации, а не об интерфейсе.