Создавайте класс и автоматически инициализируйте зависимости с помощью FakeItEasy

Можно ли создать тестируемый класс с помощью FakeItEasy, где все зависимости, объявленные в конструкторе, автоматически инициализируются с помощью подделок?

Представьте себе класс:

public class Inserting
{
    public Inserting(
        ITransactionService transactionService,
        ISharedData sharedData)
    {
        TransactionService = transactionService;
        SharedData = sharedData;
    }

    public ITransactionService TransactionService { get; }

    public ISharedData SharedData { get; }

    public void Enter()
    {
        TransactionService.StartTransaction();
    }
}

Затем я создаю все поддельные объекты в тестовой настройке и создаю свой тестируемый класс с помощью этих подделок:

public class InsertingTest
{
    private Inserting _inserting;
    private ISharedData _fakeSharedData;
    private ITransactionService _fakeTransactionService;        

    [SetUp]
    public void SetUp()
    {
        _fakeTransactionService = A.Fake<ITransactionService>();
        _fakeSharedData = A.Fake<ISharedData>();

        _inserting = new Inserting(_fakeTransactionService, _fakeSharedData);
    }

    [Test]
    public void TestEnter()
    {
        // Arrange

        // Act
        _inserting.Enter();

        // Assert
        A.CallTo(() => _fakeTransactionService.StartTransaction().MustHaveHappened();
    }
}

Но я видел в Java-мире, что при использовании Mockito и Dagger 2 вы можете сделать что-то вроде этого:

public class PhoneDialer {
    private Activity activity;
    private PhoneCallListener phoneCallListener;

    @Inject
    public PhoneDialer(Activity activity, PhoneCallListener phoneCallListener) {
        this.activity = activity;
        this.phoneCallListener = phoneCallListener;
    }
}

public class PhoneDialerTest {
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock
    PhoneCallListener phoneCallListener;

    @Mock
    Activity activity;

    @InjectMocks
    PhoneDialer dialer;

    @Test
    public void test_dialer() throws Exception {
        // Arrange

        // Act
        dialer.callNumber("abc");

        // Assert
        Mockito.verify(phoneCallListener, times(1)).startCall();
    }
}

и высмеиваемые классы автоматически инициализируются подделками. Есть ли эквивалентная процедура или функция в C# с FakeItEasy?

2 ответа

Решение

Я думаю, что вы хотите что-то вроде Автоматически вводить подделки в тестовом приспособлении с FakeItEasy. Ты используешь [Fake] отмечать подделки для инъекций и [UnderTest] отметить тип продукции для тестирования.

Мы действительно должны поместить это в документацию.

С другой стороны,

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

FakeAttribute и UnderTestAttribute накладывают то, что потенциально является хорошим структурным ограничением для вашего теста (и системы) дизайна...

[FWLIW, прежде чем гуглить это, я представлял себе следующее:

          containerBuilder.RegisterAsFakeCallingBaseType<SystemUnderTest>();

Вы можете сделать что-то подобное с источниками регистрации Autofac.

      using Autofac;
using Autofac.Core;
using Autofac.Core.Activators.Delegate;
using Autofac.Core.Lifetime;
using Autofac.Core.Registration;
using FakeItEasy;
using Xunit;

    public interface IDependOnSomething { }
    public class IImplementThat : IDependOnSomething { }

    public class CanIResolveIt
    {
        public CanIResolveIt(IDependOnSomething it)
        {
        }
    }

    public class FakeRegistrationSourceTest
    {
        [Fact]
        public void BasicTest()
        {
            var container = new ContainerBuilder();
            container.RegisterTypes<IImplementThat>().As<IDependOnSomething>();
            container.RegisterSource(new FakeRegistrationSource<CanIResolveIt>());
            var c = container.Build();
            var theFake = c.Resolve<CanIResolveIt>();
            Assert.NotNull(theFake);
        }
    }

    public class FakeRegistrationSource<T> : IRegistrationSource
        where T : class
    {
        public bool IsAdapterForIndividualComponents => false;

        public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
        {
            var swt = service as IServiceWithType;
            if (swt == null || !typeof(T).IsAssignableFrom(swt.ServiceType)) // TODO: is this the right way around?
            {
                return Enumerable.Empty<IComponentRegistration>();
            }

            var registration = new ComponentRegistration(
              Guid.NewGuid(),
              
              new DelegateActivator(swt.ServiceType, (context, @params) =>
              {
                  List<object> v = new List<object>();
                  foreach (ParameterInfo p in typeof(T).GetConstructors().Single().GetParameters())
                  {
                      v.Add(context.Resolve(p.ParameterType));
                  }

                  return A.Fake<T>(that => that.CallsBaseMethods().WithArgumentsForConstructor(v));
              }),
              new CurrentScopeLifetime(),
              InstanceSharing.None,
              InstanceOwnership.OwnedByLifetimeScope,
              new[] { service },
              new Dictionary<string, object>());

            return new IComponentRegistration[] { registration };
        }
    }

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

Очевидный недостаток — явная регистрация каждый раз, когда хочется что-то подделать. AutoFake и т. д. предлагают способы преодолеть это с подделкой почти всего по умолчанию, что вполне может быть тем, что вы хотите ... и вы можете переопределить это, если нет.]

Другие вопросы по тегам