Только что нашел решение. Вроде бы немного некрасиво, но это первая итерация, только вероятно, скоро появится более элегантная версия. Идея состоит в том, чтобы создать еще одну заглушку и сопоставить Func<>
с ней:
Я предоставлю код для моего варианта использования:
[Theory]
[InlineData(342, 31129, 3456)]
public void should_call_service_invoker_and_return_result(int number1, int number2, int expected)
{
var calculator = MockRepository.GenerateStub<ICalculator>();
calculator.Stub(_ => _.Add(number1, number2)).Return(expected);
var serviceInvoker = MockRepository.GenerateStub<ServiceInvoker<ICalculator>>();
serviceInvoker
.Stub(_ => _.Invoke(Arg<Func<ICalculator, int>>.Matches(d => d(calculator) == calculator.Add(number1, number2))))
.Return(expected);
var serviceConsumer = new ServiceConsumer(serviceInvoker);
var actual = serviceConsumer.GetAddResultFor(number1, number2);
Assert.Equal(expected, actual);
}
Расширения xUnit + используются в качестве основы тестирования. Пожалуйста, игнорируйте Theory
и InlineData
- это просто еще один способ избавиться от ненужных настроек теста
Вот код СУТ:
public class ServiceConsumer
{
private readonly ServiceInvoker<ICalculator> serviceInvoker;
public ServiceConsumer(ServiceInvoker<ICalculator> serviceInvoker)
{
this.serviceInvoker = serviceInvoker;
}
public int GetAddResultFor(int number1, int number2)
{
return serviceInvoker.Invoke(_ => _.Add(number1, number2));
}
}
public class ServiceInvoker<T>
{
public virtual R Invoke<R>(Func<T, R> func)
{
throw new NotImplementedException();
}
}
public interface ICalculator
{
int Add(int number1, int number2);
}
Надеюсь, это будет полезно. Любые предложения о том, как добавить больше красоты, приветствуются:)