-->

Using autofac with moq

2020-06-09 02:18发布

问题:

I need to register my Autofac container with specific interface, for this case I want to resolved mock.

How can I do it?

I've tried:

var AppContainer = ApplicationContainer.GetApplicationContainer();  
var cb = new ContainerBuilder();
cb.RegisterType<Mock<IStudyLoader>>().As<IStudyLoader>().SingleInstance();
cb.Update(AppContainer);

I don't want to change my code to resolve something else than IStudyLoader, but Mock<IStudyLoader> is not substitutable for IStudyLoader; e.g Mock<IStudyLoader>.Object is substitutable for IStudyLoader, but I cant register Mock<IStudyLoader>.Object because it not a type.

Correct me please; I have the feeling that I am missing something.

(I have another restriction, I can't use other container than ApplicationContainer.GetApplicationContainer())

(I think it's better to manually inject the dependency when testing, but I don't want to change the production code this time.)

回答1:

I found the solution, Yes it is possible!

  var AppContainer = ApplicationContainer.GetApplicationContainer();
  var studyLoaderMock = new Mock<IStudyLoader>().Object;
  cb.RegisterInstance(studyLoaderMock).As<IStudyLoader>();
  cb.Update(AppContainer);


回答2:

The method you are looking for is called RegisterInstance:

var mock = ...;
var cb = new ContainerBuilder();
cb.RegisterInstance(mock.Object);
var container = cb.Build();

That said, an existing container (in your case the AppContainer) that already have a registration for the interface you want to mock will not be able to resolve the instance. It will continue to resolve the production instance.

A "workaround", which I would strongly advice you to follow, is to not involve the AppContainer in your test, but rather build a container tailored for your test so you have better control of what goes in there and not. The effect is that you get to register whatever mock instance you need along with the SUT.



回答3:

Old Question, but AutoFac Now since version 4.0.1 support Moq4 and provide extra package you can install Autofac.Extras.Moq

    Install-Package Autofac.Extras.Moq

Autofac.Extras.Moq auto install both AutoFac and Moq

You needn't to create a Container and register StudyLoader. It's implicitly defined by Autofac.Extras.Moq.

Autofac.Extras.Moq is valuable for nested dependency. You don't care to register all the dependency graph. Only Mock your SystemUnderTest SUT object

You can implement you test case as given below:

         [TestFixture]
        class StudyLoaderTest
        {
            [Test]
            public void Test()
            {
                using (var mock = AutoMock.GetLoose())
                {
                    // The AutoMock class will inject a mock IStudyLoader
                    // into the StudyLoader constructor
                    //no need to create/configure a container
                    var studyLoader = mock.Create<StudyLoader>();               
                    Assert.AreEqual("hi AutoFac Moq", studyLoader.Name);
                }
            }
        }

         class StudyLoader : IStudyLoader
        {
            public string Name { get; set; } = "hi AutoFac Moq";
        }
         interface IStudyLoader
        {
            string Name { get; set; }
        }


回答4:

I don't have particular experience with autofac, but most other containers which I worked with allow to register an instance of object, that is already created. So you can create your mock, and then register mock.Object as implementation for IStudyLoader. Consult autofac documentation on how to do this.



回答5:

Since this question has been asked, there is now an AutoFac.Extras.Moq package, supported by AutoFac:

http://autofaccn.readthedocs.io/en/latest/integration/moq.html

This allows you to create on the fly dependencies within your Unit Tests.



标签: c# moq autofac