Автопереключение с LightInject plus Nsubstitute, как?
Я новичок в обеих библиотеках, и перед тем, как приступить к их использованию в большом проекте, мне нужно уточнить мои варианты автоматической блокировки кода при выполнении небольшого кода в моих модульных тестах.
Потратив некоторое время на Google, я пришел к выводу, что, в отличие от некоторых других сопряжений продуктов IOC/Mocking, готовая библиотека плагинов недоступна для LightInject+Nsubstitute, чтобы упростить объявление стандартных макетов по умолчанию на этапе аранжировки модуля. тестовое задание.
Я прочитал в документации LightInject о том, как переопределить контейнер LightInject с помощью временного расширенного фиктивного объекта только для целей модульного теста, но как насчет всех стандартных изоляций, которые не работают, которые могут затронуть модульный тест. Есть ли способ автоматизировать их создание в контейнере LightInject?
Внутреннее поведение контейнера IOC, которое я ищу:
public class LightInject.ServiceContainer
{
..
public T GetInstance<T)
{
if (( this.RegisteredInterfaces.Any( i => i.Itype == T ) == false )
&& ( this.TemporaryUnitTestOverrides.Any( i => i.Itype == T ) == false ))
&& ( /* this container is configured with an automocking delegate */ ))
return autoMockCreatorDelegate<T>.Invoke();
}
Похоже, что IProxy и Interceptors LightInject предоставляют некоторые внутренние блоки для создания фиктивных объектов, но библиотека Nsubstitute по сравнению с ним полностью функциональна.
Разъяснения о том, что я имею в виду по умолчанию, не делают ничего насмешливого и улучшенного насмешки
// default do nothing mock
var calculator = Substitute.For<ICalculator>();
// Enhanced mock that will return 3 for .Add(1,2)
var calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).Returns(3);
Очевидно, что второй улучшенный тип макета должен быть создан локально на единицу теста.
2 ответа
Я автор LightInject и очень хотел бы вам помочь.
Позвольте мне изучить это и вернуться к вам. В то же время вы можете проверить эту библиотеку в LightInject.AutopMoq, которая является сторонним вкладом в контейнер LightInject. Он использует Moq вместо NSubstitute, но общая концепция должна быть похожа на то, что вы просите.
Тем не менее, некоторое время назад я проделал некоторую работу, которая еще больше упрощает автомокинги, и я посмотрю на него и посмотрим, как это можно интегрировать с NSubstitute.
редактировать
Это супер простая реализация автоблокировки, которая работает с любой "замещающей" структурой.
using System.Diagnostics;
using LightInject;
using NSubstitute;
public interface IFoo { }
class Program
{
static void Main(string[] args)
{
var serviceContainer = new ServiceContainer();
serviceContainer.RegisterFallback((type, s) => true, request => CreateMock(request.ServiceType));
var foo = serviceContainer.GetInstance<IFoo>();
Debug.Assert(foo is IFoo);
}
private static object CreateMock(Type serviceType)
{
return Substitute.For(new Type[] { serviceType }, null);
}
}
С наилучшими пожеланиями
Бернхард Рихтер
Некоторые отзывы, как и обещано в моем комментарии к принятому ответу. Я применил предложение от автора LightInject с успехом в некоторых простых модульных тестах.
После того, как я начал работать с основами, я решил спрятать код настройки макета службы Ioc в базовом классе плюс что-то, что я назвал MockingContext, конечный результат - более чистый, более легкий код модульного теста. Класс контекста mocking также гарантирует, что для каждого настроенного типа Nsubstitute, передаваемого в службу Ioc в качестве кратковременного переопределения автоматической блокировки, существует соответствующий вызов LightInjet.Service.EndMocking( T). Это устраняет опасность того, что сконфигурированные макеты могут загрязнить предположения о автоматическом издевательстве следующего модульного теста.
В примере ClassC зависит от IFooA и IFooB (без внедрения конструктора). Для приведенного ниже модульного теста IFooA автоматически смоделируется LightInject без явного кода, тогда как IFooB настраивается с помощью вызова Nsubstitute и также передается LightInject в методе MockingContext.Add<>().
[TestClass]
public class UnitTest1 : AutoMocking
{
[TestMethod]
public void Test_1()
{
using (var mc = MockingContext)
{
// No need to mention IFooA here, LightInject will auto mock
// any interface not previously declared to it.
// Given
var mockB = mc.Add<IFooB>();
mockB.MethodY().Returns("Mock Value OOO");
var sut = new ClassC();
// When
var testResult = sut.MethodZ();
// Then
Assert.AreEqual(testResult, "MethodZ() received=Mock Value OOO");
}
}