Autofac + Moq:设置和验证。 (C#)

时间:2016-10-14 15:50:59

标签: c# unit-testing moq autofac

所以我们有一个3层Web API项目,我试图实现一些测试。

我们使用Autofac作为我们的Io​​C容器,以及它与Moq的集成库来实现一些单元测试。

从一些代码开始:

    [TestMethod]
    public void Get()
    {
        using (var mock = AutoMock.GetLoose())
        {

            // DATA LAYER
            // mock some contact objects up
            var contactsList = new List<CONTACT>
                {
                    new CONTACT { CONTACT_ID = 1, CREATE_DTIME = DateTime.Now, UPDATE_DTIME = DateTime.Now, CONTACT_TYPE = "Mocked", FORENAME = "Mock1", SURNAME = "Mock1" },
                    new CONTACT { CONTACT_ID = 2, CREATE_DTIME = DateTime.Now, UPDATE_DTIME = DateTime.Now, CONTACT_TYPE = "Mocked", FORENAME = "Mock2", SURNAME = "Mock2" },
                    new CONTACT { CONTACT_ID = 3, CREATE_DTIME = DateTime.Now, UPDATE_DTIME = DateTime.Now, CONTACT_TYPE = "Mocked", FORENAME = "Mock3", SURNAME = "Mock3" },
                    new CONTACT { CONTACT_ID = 4, CREATE_DTIME = DateTime.Now, UPDATE_DTIME = DateTime.Now, CONTACT_TYPE = "Mocked", FORENAME = "Mock4", SURNAME = "Mock4" },
                    new CONTACT { CONTACT_ID = 5, CREATE_DTIME = DateTime.Now, UPDATE_DTIME = DateTime.Now, CONTACT_TYPE = "Mocked", FORENAME = "Mock5", SURNAME = "Mock5" },
                }.AsQueryable();

            var contactsSet = new Mock<DbSet<CONTACT>>();
            contactsSet.As<IQueryable<CONTACT>>().Setup(m => m.Provider).Returns(contactsList.Provider);
            contactsSet.As<IQueryable<CONTACT>>().Setup(m => m.Expression).Returns(contactsList.Expression);
            contactsSet.As<IQueryable<CONTACT>>().Setup(m => m.ElementType).Returns(contactsList.ElementType);
            contactsSet.As<IQueryable<CONTACT>>().Setup(m => m.GetEnumerator()).Returns(contactsList.GetEnumerator());

            // mock that context
            var mockedContext = new Mock<ExampleEntities>();
            // set up context so that the contactsSet above is returned when queried.
            mockedContext.Setup(c => c.CONTACTS).Returns(contactsSet.Object);

            mock.Provide<IContactsRepository, ContactsRepository>(new TypedParameter(typeof(KCMEntities), mockedContext.Object));
            mock.Provide<IContacts, Contacts>();

            // Instantiate the controller we are performing the test on
            var testController = mock.Create<ContactsController>();

            // act
            ContactListResult contactListResult = testController.Get();

            // assert
            Assert.AreEqual(true, contactListResult.Success);
            Assert.AreEqual(5, contactListResult.ContactList.Count());
            Assert.AreEqual("Mock1", contactListResult.ContactList.First().Forename);
            Assert.AreEqual(1001, contactListResult.ContactList.First().Id); // The businesslogic layer has been doctored to add 1000 to the id...just to test it is passing through this layer..

            mock.Mock<IContactsRepository>().Verify(x => x.GetContacts(), Times.Once());

        }

    }

我们不确定这是否真的要完成,但我们正在尝试编写测试来测试/模拟在应用程序的所有层中调用控制器的操作。

IContactsRepository和IContacts分别是数据层和业务逻辑层中的服务。

我们需要在数据层模拟dbcontext以返回我们的模拟数据,并确保autofac在解析时知道为两个服务提供哪些组件:

mock.Provide<IContactsRepository, ContactsRepository>(new TypedParameter(typeof(KCMEntities), mockedContext.Object));
mock.Provide<IContacts, Contacts>();

我们设置了在解析时将模拟上下文传递到数据层的期望。这是关于IContactsRepository的具体实现的重写构造函数(尝试了非覆盖相同的问题)。默认构造函数只是新闻一个新的dbcontext,没有params。

这似乎达到了一定程度。

在我们尝试验证之前,所有断言都没有问题:

mock.Mock<IContactsRepository>().Verify(x => x.GetContacts(), Times.Once());

这会引发错误:

"Unable to cast object of type 'Data.Repositories.ContactsRepository' to type 'Moq.IMocked``1[Data.Interfaces.IContactsRepository]'."

现在出于显而易见的原因,我们希望使用验证来验证我们所拥有的组件/服务上是否调用了某些方法。

我们尝试了许多设置变体,例如mock.Mock>IContacts>().Setup(....等等,并没有设法解决/正确设置。

基本上我们要么在尝试像这样测试时做一些基本上有缺陷的事情,要么希望我们只是做错误的设置。

有关如何实现这一目标的任何建议吗?

提前感谢您的帮助。

0 个答案:

没有答案