Breaking Changes in Autofac.Extras.Moq
If, like me, you are a fan of Autofac and Moq, popular frameworks for dependency injection and mocking for .NET, respectively, you probably already know about Automoq.
With Automoq, our tests tend to be much more concise, without all the ceremony inherent to using a framework like Moq.
A test that would traditionally look something like this:
1[Fact]
2
3public void TestingWithMoq()
4{
5 var oneMockedService = new Mock<IOneService>();
6 oneMockedService.Setup(x => x.DoStuff(It.Is<string>((s) => s.Equals("hello"))))
7 .Returns("World");
8 var anotherMockedService = new Mock<IAnotherService>();
9 anotherMockedService.Setup(x => x.DoAnotherThing(It.IsAny<string>()));
10 var app = new AmazingApp(oneMockedService.Object, anotherMockedService.Object);
11 var result = app.Execute("hello");
12
13 result.ShouldBe("World");
14}
Using Automoq, we get:
1[Fact]
2public void TestingWithAutoMoq()
3{
4 using (var mock = AutoMock.GetLoose())
5 {
6 mock.Mock<IOneService>()
7 .Setup(x => x.DoStuff(It.Is<string>((s) => s.Equals("hello"))))
8 .Returns("World");
9
10 var result = mock.Create<AmazingApp>().Execute("hello");
11
12 result.ShouldBe("World");
13 }
14}
In my humble opinion, it's much better. I only have to worry about setting up the dependencies that matter to me, and Automoq provides a standard implementation for the others.
Since not everything is free, we have a bit of extra work when we have to test a class where one of the dependencies is a concrete instance. Before version 5, we could use mock.Provide to indicate to the framework that we want to use a concrete implementation of our dependency:
In this case, IOneService remains a Mock, but for IAnotherService, the framework will inject the AnotherServiceFake implementation.
1[Fact]
2public void TestingWithProvide()
3{
4 using (var mock = AutoMock.GetStrict())
5 {
6 mock.Mock<IOneService>()
7 .Setup(x => x.DoStuff(It.Is<string>((s) => s.Equals("hello"))))
8 .Returns("World");
9
10 mock.Provide<IAnotherService>(new AnotherServiceFake());
11 var result = mock.Create<AmazingApp>().Execute("hello");
12
13 result.ShouldBe("World");
14 }
15}
In version 5, the Provide extension no longer exists. Instead, we can configure the setup by passing an Action to configure the container when creating Automock:
1[Fact]
2public void TestingWithBuilderAction()
3{
4 using (var mock = AutoMock.GetStrict(
5 builder => builder.RegisterInstance(new AnotherServiceFake()).As<IAnotherService>())
6 )
7 {
8 mock.Mock<IOneService>()
9 .Setup(x => x.DoStuff(It.Is<string>((s) => s.Equals("hello"))))
10 .Returns("World");
11 var result = mock.Create<AmazingApp>().Execute("hello");
12
13 result.ShouldBe("World");
14 }
15}
This last option becomes even more powerful when we realize that Automoq exposes the ContainerBuilder, and with it, we can do all of our dependency configuration, including using Modules. But that's for another post!