Often we end up in a situation where constructor call on the target type requires us to include a config file in our test project or requires firing up some external process. To better illustrate this if we create an entity framework data container either new or from an existing database , we will likely to end up with an entry point class that requires either a valid connection string to be passed or if we expand the default constructor we might see this:
- /// <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 make the following test pass with the above constructor:
- 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 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 the one shown below:
- 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 which is on the other hand is not possible in C# 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 and things will work just nicely.
Hope that you will find the Constructor.Mocked feature useful. You can download the project for this post here EntityFramework01.zip. Finally If you like NuGet, you can also try install-package JustMock to grab the latest build.