Автопереключение с 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");
        }
    }
Другие вопросы по тегам