Mocking database with DalFactory and Avoiding Shared Fixtures

Mocking database with DalFactory and Avoiding Shared Fixtures

Old forum URL: forums.lhotka.net/forums/t/11285.aspx


decius posted on Friday, April 06, 2012

 

 

So I really enjoy the wonderful solution posed by mocking the dal, illustrated with the project tracker sample. It's simple and sweet and really decouples your data layer. Still for testing though, I've continued to run into a specific problem, which is that this patter will pretty much force me to share the mocked database among all tests. Shared fixture == code smell. Sometimes I want to isolate or stub my tests for a specific data configuration only.

Sure, we could make multiple mock libraries for testing and toggle the app config on each test, but one for each isolated or data stubbed test? No good. A lot of mocking libraries present some solutions for fakes nicely for this but they usually depend on things like dependency injection - which with CSLA's serialization, reflection, and dataportal this becomes messy and more difficult. They cater well in single tiered architectures, But the dataportal is there for a reason and it poses several challenges for testing. This somewhat dated article from 2009 sums up my findings pretty well. But it's old and I imagine a lot of people have come up with solutions since then that I'm unaware of http://richallen.blogspot.com/2009/04/unit-testing-csla-with-type-mock.html

I had fiddled with the Moles framework after seeing it at a conference (now called fakes framework in vs2012) which allows for literally "faking" any method on your assemblies for a test using anon delegates. Fabulous! Syntax is super simple, and working with it is built right into the IDE. Fakes can be coded right into the test method for easy self explaining and clear test code. On the surface, this looked fantastic, but in implementing it, it just bogs VS down and productivity hit the floor in dealing with it. No dice. Maybe MS will improve it in future versions but my experiences were lousy.

So I'd tried several other things and I think I've settled on a possible solution, so I'd like to hear anyone's thoughts, as I'm sure many have come up with solutions better than mine.

Using the exact same pattern as the Mocked database pattern in the CSLA Project Tracker sample code, I made a slight modification to the DalManager in my Mocking library. Here's the dalmanager for the mocks:

 

public class DalManager : IDalManager

       {

 

              #region Overridden Mocks

 

              private static Dictionary<Type, object> _OverriddenMocks = new Dictionary<Type, object>();

 

              public static T GetOverriddenMock<T>()

              {

                     return (T)_OverriddenMocks[typeof(T)];

              }

 

              public static void ClearOverriddenMocks()

              {

                     _OverriddenMocks.Clear();

              }

 

              public static void AddOverriddenMock<T>(T dalMock)

              {

                     _OverriddenMocks.Add(typeof(T), dalMock);

              }

 

              #endregion

 

 

 

              private static string _typeMask = typeof(DalManager).FullName.Replace("DalManager", @"{0}");

 

              public T GetProvider<T>() where T : class

              {

                     if (_OverriddenMocks.ContainsKey(typeof(T)))

                           return (T)_OverriddenMocks[typeof(T)];

 

                     var typeName = string.Format(_typeMask, typeof(T).Name.Substring(1));

                     var type = Type.GetType(typeName);

                     if (type != null)

                     {

                           return Activator.CreateInstance(type) as T;

                     }

                     else throw new NotImplementedException(typeName);

              }

 

              public void Dispose()

              { }

 

              public void SubmitChanges()

              { }

       }

 

Not really much change, but I've added the static dictionary which can be used in the tests to add a stub for that specific test and some public generic methods to deal with the type conversion (that's just my personal API stlye of choice, but isn't necessary if it doesn't float your boat). So, now, using your favorite mocking framework you can easily add your stubbed dal provider in as needed. Here's a quick example. Sorry, this is a real world test, so it's not dumbed down for demonstration. Basically, the point is that it allows me to successfully stub out data access as needed inline to isolate the test:

 

 

 

              [TestMethod]

              public void When_get_email_from_aod_selected_should_fetch_email_from_aod()

              {

                     // arrange

                     var fixture = MigrantFixture.Create();

                     fixture.Accessor.FetchEmailFromAod = true;

                     var mockAodService = MockRepository.GenerateMock<IAodService>();

                     fixture.Accessor._aodClient = mockAodService;

 

                     var stubEmps = MockRepository.GenerateStub<IEmpsDal>();

                     stubEmps.Stub(x => x.FetchFromM3(fixture.Accessor.Co)).Return(

                     new List<EmpDto>()

                           {

                                  new EmpDto() { ssn = "111-11-1111", id = "1" }

                           });

                     DalMock.DalManager.AddOverriddenMock<IEmpsDal>(stubEmps);

 

                     var stubEmpList = MockRepository.GenerateStub<IEmpListDal>();

                     stubEmpList.Stub(x => x.GetEmpListFromM3(fixture.Accessor.Co)).Return(

                     new List<EmpListDto>()

                           {

                                  new EmpListDto(){ Ssn = "111-11-1111", Id = "1" }

                           });

                     DalMock.DalManager.AddOverriddenMock<IEmpListDal>(stubEmpList);

 

                     // act

                     fixture.Accessor.ProcessAndSaveEmps();

 

 

                     // assert

                     mockAodService.AssertWasCalled(x => x.GetEmployeeEssEmail("111-11-1111"));

              }

 

Note though, you'll have to consider teardown of the overridden mocks to prevent the erratic and unrepeatable tests. Just simply clear the static dictionary on your testing framework's test test cleanup. IE, MSUnit just use the test cleanup attribute on a method in your test class:

 

              [TestCleanup()]

              public void MyTestTeardown()

              {

                     Aps.SaasHr.DalMock.DalManager.ClearOverriddenMocks();

              }

 

The only catch, I suppose, is that when faking your dal, you have to consider any validation on your object (make sure you load up valid data). So this seems to work good for me, but what are others doing to address this? Feedback welcomed :)

 

 

 

 

RockfordLhotka replied on Friday, April 06, 2012

A lot of patterns for this assume single tier scenarios, which can complicate matters. Obviously you also want to avoid complicating the real Dal or the provider indirection code just to enable testing.

One thing to consider is passing out of band data from the test to the mock Dal using ApplicationContext.ClientContext. No real code would ever see of use this, but it provides a channel by which the test code can pass data or metadata to the mock Dal so that Dal can change its behavior,

One Twix is that the default ApplicationContext provider shares context on the client, so if you run tests in parallel using the mstest multi threading support you need to supply a threadsafe context provider (not hard to do).

decius replied on Monday, April 09, 2012

RockfordLhotka

A lot of patterns for this assume single tier scenarios, which can complicate matters. Obviously you also want to avoid complicating the real Dal or the provider indirection code just to enable testing.

Excellent. My thoughts exactly, sounds like I'm on the right track with making modifications to just the mock dal. 

 

 

RockfordLhotka

One thing to consider is passing out of band data from the test to the mock Dal using ApplicationContext.ClientContext. No real code would ever see of use this, but it provides a channel by which the test code can pass data or metadata to the mock Dal so that Dal can change its behavior,

Making use of the ClientContext is a splendid idea! If I understand what you're suggesting, I could pass a switch value from a test that would tell my mock dal which test data to load. The only downside I see to this (for me) is that the actual data has to be loaded/defined inside the dal itself. I really like being able to clearly define stubs in the test code itself (like with lambdas), because I feel it lends to self documented and intent revealing test code. While some might not care about this, this kind of test quality is suggested by Gerard Meszaros in xUnitPatterns and I believe I've read a blog or two where Martin Fowler has suggested the same. If it weren't for serialization, I would just load the DTO to the ClientContext to solve this problem, but alas, that won't work easily - DTO would have to be serialized. So I'm still leaning back to my proposed solution of a simple static dictionary on the mock dal.

 

 

RockfordLhotka

One Twix is that the default ApplicationContext provider shares context on the client, so if you run tests in parallel using the mstest multi threading support you need to supply a threadsafe context provider (not hard to do).

Yeah, my proposed static Mock dictionary also suffers from this very problem. I'm not familiar with writing a thread safe context provider, but I figured I could just make the ManagedThreadId+Type the dictionary key. The teardown would solve the problem of re-used threads, so I can't really think of any reason this wouldn't work. I'll give it a shot maybe this week. 

decius replied on Monday, April 16, 2012

Just wanted to report back and say that what I've been implementing seems to work fine. I'm essentially injecting my Mocks this way fine. 

I should note, I did come across this other link below where JonnyBee answers to someone else trying to do exactly what I'm setting out to accomplish here. It might be a more elegant way of doing what I'm trying to do by using MEF. 

http://forums.lhotka.net/forums/p/10022/47062.aspx

I'm a bit too far into this project to try to rewrite everything I would need to for this though.

In all, I can't say the solution that I'm implementing is bad. It's relatively simple, and doesn't require a lot of work. The only downside I'm seeing is that to work around supporting multithreaded testing it requires a little more work to keep a key on each thread in your mocked dal. And more imortantly (to me) is that the test code where I inject the mock might seem somewhat foreign to some people. 

 

Copyright (c) Marimer LLC