Фальсифицирующие фабрики делегатов в сервисных библиотеках с 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");

... тогда это может сработать.

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