While unit testing a target type, it is likely that the test is failing during object creation because we forgot to include a mandatory configuration file or a line in the constructor is throwing exception because it is making call to some external service or data store which on the other hand requires a little more orchestration to get things going . To better illustrate this, let’s create an entity framework data container either new or from an existing database. Once we have completed the required steps, there will be an entry-point class where we will notice the following default constructor:
- /// <summary>
- /// Initializes a new NorthwindEntities object using the connection string found in the 'NorthwindEntities' section of the application configuration file.
- /// </summary>
- public NorthwindEntities() : base("name=NorthwindEntities", "NorthwindEntities")
- this.ContextOptions.LazyLoadingEnabled = true;
The comment clearly shows that by default it will search for a connection string named “NorthwindEntities” in the configuration file. Though this is not an ideal case where it makes the class more production oriented less TDD friendly (if you think it in a TDD purist way) but to avoid this kind of situation the newest release of Telerik JustMock (Free / Commercial) includes a way to mock such case comprehensively. Thus making it flexible for testers who don’t need to include a configuration file or initialize a default service.
Using the JustMock free edition, I can now easily test the above data container without going through any unnecessary configuration hassle:
- public void ShouldAssertWhenSaveOperationIsExpected()
- var context = Mock.Create<NorthwindEntities>(Constructor.Mocked);
- Mock.Arrange(() => context.SaveChanges(Arg.IsAny<SaveOptions>())).MustBeCalled();
The key here is the Consturctor.Mocked overload in Mock.Create<T>. By default it is set Constructor.NotMocked as general but incase your constructor is throwing some unknown exception and you have little control over its codebase then this could be just it.
# region Developer’s log:
As the feature is supported in JustMock free edition, it is right to say that there is no profiler involved. Therefore, it is not possible to use FormatterServices in that regard :
- var context = FormatterServices.GetSafeUninitializedObject(typeof(NorthwindEntities));
If we just open up the NorthwindEntities class in IL dissembler , we will see something like this:
- IL_0000: ldarg.0
- IL_0001: ldarg.1
- IL_0002: ldstr "NorthwindEntities"
- IL_0007: call instance void [System.Data.Entity]System.Data.Objects.ObjectContext::.ctor(string,
- IL_000c: nop
- IL_000d: nop
- IL_000e: ldarg.0
- IL_000f: call instance class [System.Data.Entity]System.Data.Objects.ObjectContextOptions [System.Data.Entity]System.Data.Objects.ObjectContext::get_ContextOptions()
- IL_0014: ldc.i4.1
- IL_0015: callvirt instance void [System.Data.Entity]System.Data.Objects.ObjectContextOptions::set_LazyLoadingEnabled(bool)
- IL_001a: nop
- IL_001b: nop
- IL_001c: ret
Here on line 4 it is first calling the base constructor which is actually the case for all .net objects. Even If the class has no base, .net framework will still do an instance call to System.Object itself. But it is possible to skip the call during proxy initialization dynamically that framework wont let you do otherwise if the base class has no default constructor. Of course, this wont work with sealed class in that case profiler is the only resort. Also, Silverlight runtime does not allow it but you can still reference Silverlight class library from .net test project to make things work.
Hope that you will find the Constructor.Mocked feature useful. You can download sample the project for this post here EntityFramework01.zip. Finally If you like NuGet, you can also try install-package JustMock to grab the latest bits.