Mocking constructor

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:

 

  1. /// <summary>
  2. /// Initializes a new NorthwindEntities object using the connection string found in the 'NorthwindEntities' section of the application configuration file.
  3. /// </summary>
  4. public NorthwindEntities() : base("name=NorthwindEntities", "NorthwindEntities")
  5. {
  6.     this.ContextOptions.LazyLoadingEnabled = true;
  7.     OnContextCreated();
  8. }

 

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:

  1. [TestMethod]
  2. public void ShouldAssertWhenSaveOperationIsExpected()
  3. {
  4.     var context = Mock.Create<NorthwindEntities>(Constructor.Mocked);
  5.  
  6.     Mock.Arrange(() => context.SaveChanges(Arg.IsAny<SaveOptions>())).MustBeCalled();
  7.  
  8.     context.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
  9.  
  10.     Mock.Assert(context);
  11. }

 

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 :

  1. 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:

 

  1. IL_0000:  ldarg.0
  2. IL_0001:  ldarg.1
  3. IL_0002:  ldstr      "NorthwindEntities"
  4. IL_0007:  call       instance void [System.Data.Entity]System.Data.Objects.ObjectContext::.ctor(string,
  5.                                                                                                 string)
  6. IL_000c:  nop
  7. IL_000d:  nop
  8. IL_000e:  ldarg.0
  9. IL_000f:  call       instance class [System.Data.Entity]System.Data.Objects.ObjectContextOptions [System.Data.Entity]System.Data.Objects.ObjectContext::get_ContextOptions()
  10. IL_0014:  ldc.i4.1
  11. IL_0015:  callvirt   instance void [System.Data.Entity]System.Data.Objects.ObjectContextOptions::set_LazyLoadingEnabled(bool)
  12. IL_001a:  nop
  13. IL_001b:  nop
  14. 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.

#endregion

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. 

 

Thanks

Read the complete post at http://feedproxy.google.com/~r/burncsharp/~3/3dHTaZZ6d8I/mocking-constructor.aspx

Published Tue, Mar 22 2011 9:35 by Mehfuz's WebLog
Filed under: , , ,