Unit test through Autofac module to achieve 100% code coverage

We have a basic library that does complex calculations, and we consider it critical, and we want this library to have 100% code coverage. We now have 96%, which is great, but we cannot get 100% because of this class:

public class IoCModule : Autofac.Module { protected override void Load(Autofac.ContainerBuilder builder) { builder.RegisterType<SomeMathServiceA>().As<ISomeMathServiceA>(); builder.RegisterType<SomeMathServiceB>().As<ISomeMathServiceB>(); //... more registrations } } 

I don’t know how to test it, or if we really need to test it.

I tried the unit test, which take this module and create an IContainer , and solve every case dependency, but some services access DB files and configuration files, which are very complex in this context.

Done !!!! enter image description here

+6
source share
2 answers

Disclaimer: the unit test class is not considered reasonable

(author)

I think with the help of unit testing you mean "unit level tests of the class", where the unit is the class. If you want to test the IoCModule , you should use component / library level testing, where you test the entire library to see if it works correctly. This (should) include IoCModule - and all other things in the library. It is usually impractical to achieve 100% coverage of branches using tests at this level, but a combination of tests at this level + unit-level tests of a class level provide very good reliability of the test. I would also say that it is better to achieve coverage of 80%, and not just unit tests at the class level. Although each class may work exactly according to the test, everything may not work as intended. This is why you should perform component level tests.

How to check if a type is registered:

Now, if you are still not sure about the tests, look no further, you can do it as follows:

 public class MyModuleTest { private IContainer container; [TestFixtureSetUp] public void TestFixtureSetUp() { var containerBuilder = new ContainerBuilder(); // register module to test containerBuilder.RegisterModule<MyModule>(); // don't start startable components - // we don't need them to start for the unit test this.container = containerBuilder.Build( ContainerBuildOptions.IgnoreStartableComponents); } [TestCaseSource(typeof(TypesExpectedToBeRegisteredTestCaseSource))] public void ShouldHaveRegistered(Type type) { this.container.IsRegistered(type).Should().BeTrue(); } [TestFixtureTearDown] public void TestFixtureTearDown() { this.container.Dispose(); } private class TypesExpectedToBeRegisteredTestCaseSource : IEnumerable<object[]> { private IEnumerable<Type> Types() { // whatever types you're registering.. yield return typeof(string); yield return typeof(int); yield return typeof(float); } public IEnumerator<object[]> GetEnumerator() { return this.Types() .Select(type => new object[] { type }) .GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } } 

This gives a test result, for example: enter image description here

therefore, each type is reported separately.

Wow, that was easy - so what's the problem again?

Now in the example above, you can see that the test passes for single (= float ). Now look at the module:

 public class MyModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<float>(); } } 

when we are actually trying to resolve float :

 container.Resolve<float>(); 

here's what happens:

Autofac.Core.DependencyResolutionException: constructors of type "System.Single" cannot be found by searching for the constructor "Autofac.Core.Activators.Reflection.DefaultConstructorFinder".

Of course, we could just adapt the test to execute Resolve(Type t) instead of using IsRegistered(Type t) - however, there are many other ways to make a test pass, but the implementation failed. For instance:

  • type binding to using builder.RegisterInstance<IFoo>(null)
  • change the service life / scope so that it does not work properly.
+4
source

I finally found a way to test it. The autofac module has a Configure method that registers components. Here is how I did it:

 public class CheckRegistrations { [Test] public void Should_Have_Register_Types() { //Arrange var typesToCheck = new List<Type> { typeof (ISomeMathServiceA), typeof (ISomeMathServiceB) }; //Act var typesRegistered = this.GetTypesRegisteredInModule(new IoCModule()); //Arrange Assert.AreEqual(typesToCheck.Count, typesRegistered.Count()); foreach (var typeToCheck in typesToCheck) { Assert.IsTrue(typesRegistered.Any(x => x == typeToCheck), typeToCheck.Name + " was not found in module"); } } private IEnumerable<Type> GetTypesRegisteredInModule(Module module) { IComponentRegistry componentRegistry = new ComponentRegistry(); module.Configure(componentRegistry); var typesRegistered = componentRegistry.Registrations.SelectMany(x => x.Services) .Cast<TypedService>() .Select(x => x.ServiceType); return typesRegistered; } } 
+3
source

All Articles