This project has moved and is read-only. For the latest updates, please go here.

Effort and Shrim (Visual Studo Fakes Assembly)

Mar 14, 2013 at 12:06 AM
Edited Mar 14, 2013 at 3:47 PM
Hi,

First of all: this project is awesome! You did a very good job!

What is the right way of testing a method that uses Entity model(s), without modifying code inside the method? For example: testing existing WCF methods without changing them.
I tried to use Shrim like this:
[TestMethod]
public void TestMethod1()
{
  using (ShimsContext.Create())
  {
     ShimMyMasterDataContainer.Constructor =
       myModel => Effort.ObjectContextFactory.CreateTransient<MyMasterDataContainer>();

     var classToTest = new Class1();
     int result = classToTest.DoSomeEntityStuff();

     Assert.AreEqual(1, result);
  }
}
but it throws an exception:
Test method EntityEffortTest.UnitTest1.TestMethod1 threw exception: 
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. 
---> System.InvalidOperationException: ValueFactory attempted to access the Value property of this instance.
Result StackTrace:  
at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at System.Lazy`1.get_Value()
   at Effort.Internal.Caching.ConcurrentCache`2.Get(TKey key, Func`1 factory)
   at Effort.Internal.Caching.ObjectContextTypeStore.GetObjectContextType(String entityConnectionString, String effortConnectionString, Type objectContextType, Func`1 objectContextTypeFactoryMethod)
   at Effort.ObjectContextFactory.CreateType[T](String entityConnectionString, Boolean persistent, IDataLoader dataLoader)
   at Effort.ObjectContextFactory.CreateTransientType[T]()
   at Effort.ObjectContextFactory.CreateTransient[T]()
   at EntityEffortTest.UnitTest1.<TestMethod1>b__0(MyMasterDataContainer myModel) in c:\.............\EntityEffort\EntityEffortTest\UnitTest1.cs:line 22
   at MyModel.MasterData.MyMasterDataContainer..ctor() in c:\.........\MyModel\MasterData\MasterDataExtension.cs:line 25    
 --- End of inner exception stack trace ---
    at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance[T]()
   at Effort.ObjectContextFactory.GetDefaultConnectionString[T]()
   at Effort.ObjectContextFactory.<>c__DisplayClass1`1.<CreateType>b__0()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at System.Lazy`1.get_Value()
   at Effort.Internal.Caching.ConcurrentCache`2.Get(TKey key, Func`1 factory)
   at Effort.Internal.Caching.ObjectContextTypeStore.GetObjectContextType(String entityConnectionString, String effortConnectionString, Type objectContextType, Func`1 objectContextTypeFactoryMethod)
   at Effort.ObjectContextFactory.CreateType[T](String entityConnectionString, Boolean persistent, IDataLoader dataLoader)
   at Effort.ObjectContextFactory.CreateTransientType[T]()
   at Effort.ObjectContextFactory.CreateTransient[T]()
   at EntityEffortTest.UnitTest1.<TestMethod1>b__0(MyMasterDataContainer myModel) in c:\..............\EntityEffort\EntityEffortTest\UnitTest1.cs:line 22
   at MYModel.MasterData.MyMasterDataContainer..ctor() in c:\...............\MyModel\MasterData\MasterDataExtension.cs:line 25
   at EntityEffort.Class1.CreateStuff() in c:\.............\EntityEffort\EntityEffort\Class1.cs:line 23
   at EntityEffortTest.UnitTest1.TestMethod1() in c:\..............\EntityEffort\EntityEffortTest\UnitTest1.cs:line 24


....
I have an App.config file with the connectionstring.

Thanks,
László
Mar 14, 2013 at 2:05 PM
Edited Mar 14, 2013 at 2:33 PM
Hello,

Thank you for your kind words :)

I am not familiar with Shrim, but at first I am curious if the thrown InvalidOperationException had an inner exception.
Mar 14, 2013 at 3:52 PM
Edited Mar 14, 2013 at 4:12 PM
Hello,

I modified my first message to display the whole exception message.
This is a good video about Visual Studio Fakes: http://vimeo.com/43549084

MasterDataExtension.cs is a partial class for my model.

Anyway, even with or without Shrims, what is the appropriate way of using Effort to test methods (which use Entity) without modifying the method, or with least modifications?
Mar 14, 2013 at 4:18 PM
Edited Mar 14, 2013 at 4:22 PM
Okey, perhaps I understand the problem now. Since you haven't specified the entity connection string, Effort tries to determine the default one. For this, it instantiates your ObjectContext using its default constructor and reads its connection string. Because of Schrim (presumably), it is not able instantiate it, there is some black magic underneath :).

Try to specify the entity connection string explicitly in the CreateTransient method.

By the way, I would recommend to use constructor injection in your WCF services. It might need lot of work at first, but it is a really clean approach.
Mar 14, 2013 at 4:22 PM
Hello,

I modified my first message to display the whole exception message.
This is a good video about Visual Studio Fakes: http://vimeo.com/43549084

Anyway, even with or without Shrims, what is the appropriate way of using Effort to test WCF methods (which use Entity) without modifying the method, or with least modifications?
Mar 19, 2013 at 12:24 PM
Edited Mar 19, 2013 at 12:24 PM
Pardon? You have replied the same as before.

Did invoking ObjectContextFactory.CreateTransient("name=connectionString") help you?
Mar 21, 2013 at 4:26 PM
Sorry for my previous (duplicate) reply, please delete it if you can.

This form of CreateTransiend neither didnt't help.

I started studying about dependency injection. Effort will be useful there, as a kind of test double, like mocking.
Mar 22, 2013 at 10:32 PM
Edited Mar 22, 2013 at 10:34 PM
Sorry to hear that. My next idea would be the creation a static factory method:
public static ShimMyMasterDataContainer Create()
{
   return new ShimMyMasterDataContainer();
}
Then changing the appropriate "new ShimMyMasterDataContainer()" expressions to "Factory.Create()" simply with find and replace.

After that you should be able to"override" the Create method with Shrim.

However, I am glad to hear you started exploring dependency injection. I have written an blog post about it that might give you some ideas.