Всегда замораживать издевки с использованием AutoFixture, XUnit и Moq

121
17

Я использую расширения AutoFixture, Moq и XUnit (атрибут [Theory]), как описано в этом сообщении в блоге http://blog.ploeh.dk/2010/10/08/AutoDataTheorieswithAutoFixture.


Я заметил, что большинство модульных тестов выглядит следующим образом:


[Theory, AutoMoqData]
public void Test(
[Frozen] Mock<IServiceOne> serviceOne,
[Frozen] Mock<IServiceTwo> serviceTwo,

MyClass classUnderTest)
{
// Arrange
serviceOne
.Setup(m => m.Get(It.IsAny<int>()));

serviceTwo
.Setup(m => m.Delete(It.IsAny<int>()));

// MyClass has a constructor with arguments for IServiceOne, and IServiceTwo
// classUnderTest will use the two mocks specified above

// Act
var result = classUnderTest.Foo();

// Assert
Assert.True(result);
}


В отличие от того, чтобы всегда украшать издевательства с помощью [Frozen], есть ли способ настроить прибор, чтобы всегда замораживать mocks?


Здесь атрибут AutoMoqData:


public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}

спросил(а) 2021-01-14T01:01:20+03:00 1 неделя назад
1
Решение
120

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


public class MemoizingBuilder : ISpecimenBuilder
{
private readonly ISpecimenBuilder builder;
private readonly ConcurrentDictionary<object, object> instances;

public MemoizingBuilder(ISpecimenBuilder builder)
{
this.builder = builder;
this.instances = new ConcurrentDictionary<object, object>();
}

public object Create(object request, ISpecimenContext context)
{
return this.instances.GetOrAdd(
request,
r => this.builder.Create(r, context));
}
}


Обратите внимание, что он украшает другой ISpecimenBuilder, но запоминает все значения перед их возвратом. Если тот же запрос поступит снова, он вернет memoized значение.


Пока вы не можете расширить AutoMoqCustomization, вы можете реплицировать то, что он делает (это всего две строки кода), и использовать MemoizingBuilder вокруг него:

public class AutoFreezeMoq : ICustomization
{
public void Customize(IFixture fixture)
{
if (fixture == null)
throw new ArgumentNullException("fixture");

fixture.Customizations.Add(
new MemoizingBuilder(
new MockPostprocessor(
new MethodInvoker(
new MockConstructorQuery()))));
fixture.ResidueCollectors.Add(new MockRelay());
}
}


Используйте AutoFreezeMoq вместо AutoMoqCustomization. Он заморозит все mocks и все интерфейсы и абстрактные базовые классы, созданные из этих mocks.


public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoFreezeMoq()))
{
}
}

ответил(а) 2021-01-14T01:01:20+03:00 1 неделя назад
84

Я закончил копирование кода из класса AutoDataAttribute и изменил его, указав FreezingCustomization.


Это результирующий атрибут.

public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}

public override IEnumerable<object[]> GetData(System.Reflection.MethodInfo methodUnderTest, Type[] parameterTypes)
{
var specimens = new List<object>();
foreach (var p in methodUnderTest.GetParameters())
{
CustomizeFixture(p);
if (p.ParameterType.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IMock<>)))
{
var freeze = new FreezingCustomization(p.ParameterType, p.ParameterType);
this.Fixture.Customize(freeze);
}
var specimen = Resolve(p);
specimens.Add(specimen);
}

return new[] { specimens.ToArray() };
}

private void CustomizeFixture(ParameterInfo p)
{
var dummy = false;
var customizeAttributes = p.GetCustomAttributes(typeof(CustomizeAttribute), dummy).OfType<CustomizeAttribute>();
foreach (var ca in customizeAttributes)
{
var c = ca.GetCustomization(p);
this.Fixture.Customize(c);
}
}

private object Resolve(ParameterInfo p)
{
var context = new SpecimenContext(this.Fixture);
return context.Resolve(p);
}
}

ответил(а) 2021-01-14T01:01:20+03:00 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема