Фальсифицирующие фабрики делегатов в сервисных библиотеках с Autofac и Moq
У меня есть простое консольное приложение, которое использует Autofac в качестве контейнера IoC.
class Program
{
static IContainer container;
static void Main(string[] args)
{
container = Configure();
Run();
}
private static void Run()
{
using (var scope = container.BeginLifetimeScope())
{
var t = scope.Resolve<ITest1>();
var s = t.TestMethod1("");
Console.WriteLine(s);
}
}
private static IContainer Configure()
{
var builder = new ContainerBuilder();
builder.RegisterType<TestClass1>()
.As<ITest1>();
builder.RegisterType<TestClass2>()
.As<ITest2>();
return builder.Build();
}
}
Приложение вызывает метод "TestMethod1" в "TestClass1".
public interface ITest1
{
string TestMethod1(string s);
}
public class TestClass1 : ITest1
{
ITest2 f;
public TestClass1(Func<ITest2> test2Factory)
{
f = test2Factory();
}
public string TestMethod1(string s)
{
var r = string.Empty;
r = f.TestMethod2(s);
r += ":TestMethod1";
return r;
}
}
TestClass1 имеет зависимость от TestClass2, который объявляет фабрику делегатов для Autofac для использования с конструктором TestClass1.
public interface ITest2
{
string TestMethod2(string s);
}
public class TestClass2 : ITest2
{
public delegate TestClass2 Factory();
public virtual string TestMethod2(string s)
{
return ":TestMethod2";
}
}
Это все работает, как и ожидалось - Autofac разрешает зависимость TestClass2, и я получаю вывод ":TestMethod2:TestMethod1".
Теперь я хочу смоделировать TestClass2, используя Moq и расширения Autofac.Extras.Moq. Я добавляю следующий метод в консольное приложение и вызываю его из метода Program Main.
private static void Test()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<TestClass2>()
.Setup(t => t.TestMethod2(""))
.Returns(":NOT_TEST_METHOD2");
var s = mock.Create<TestClass1>();
var r = s.TestMethod1("cheese");
Console.WriteLine(r);
}
}
Теперь я получаю вывод ":TestMethod1", когда ожидаю ":NOT_TEST_METHOD2:TestMethod1". Кажется, издевательство не было названо. Это подтверждается, когда я перешагиваю код.
Я также попытался разрешить макет с помощью mock.Provide(), как было предложено в другом месте (см. Ниже). Все еще не повезло.
var wc = Moq.Mock.Of<TestClass2>(f => f.TestMethod2("") == ":NOT_TEST_METHOD2");
Func<string, ITest2> factory = x => wc;
mock.Provide(factory);
Это кажется очень простым сценарием, но я нигде не нашел рабочего ответа. Кто-нибудь может увидеть, что я делаю не так? Спасибо за любую помощь!
2 ответа
Спасибо Тревис. Ваше предложение не сработало для меня, но заставило меня задуматься о проблеме по-другому, а шаг назад заставил меня осознать, что я искал комплексное решение, в котором оно не требовалось. А именно, что требовался только Moq, расширений Autofac AutoMock не было. Сработал следующий код:
private static void Test()
{
Func<ITest2> func = () =>
{
var x = new Mock<ITest2>();
x.Setup(t => t.TestMethod2("")).Returns(":NOT_TEST_METHOD2");
return x.Object;
};
var s = new TestClass1(func);
var r = s.TestMethod1("");
}
Ответ на этот вопрос был получен с помощью Moq для макетирования параметра конструктора Func<> и проверки его вызова дважды.
Я не пользуюсь AutoMock
поддержка, но я знаю мой Autofac, так что я могу дать ему шанс.
Это выглядит как TestClass1
занимает ITest2
и не TestClass2
в его конструкторе, я думаю, если вы переключились на это:
mock.Mock<ITest2>()
.Setup(t => t.TestMethod2(""))
.Returns(":NOT_TEST_METHOD2");
... тогда это может сработать.