chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
I am using StructureMap to inject the data access layer into a CSLA business object. I want to setup tests that can test the interface instead of the concrete implementations of the DAL. I'm not sure if this is a valid approach but it would seem to make the tests less brittle if they didn't depend on a concrete implementation but instead would test whatever is currently configured.

I have a test of a concrete class working:

[Test, Isolated]
public void TM_ValidDTO_ShouldLoad()
{
    var dal = Isolate.Fake.Instance<AdjustmentCategoryData>();
    Isolate.Swap.NextInstance<AdjustmentCategoryData>().With(dal);
    Isolate.WhenCalled(() => dal.GetCategory(1)).WillReturn(new AdjustmentCategoryDTO { CategoryID = 1 });

    var category = AdjustmentCategory.GetCategory(1);

    Assert.AreEqual(1, category.CategoryID);
    Assert.IsFalse(category.IsActive);
}


When I try to change this test to use the interface I get the following exception:

TypeMock.TypeMockException:
*** Cannot type mock Interfaces or Abstract classes use MockObject

How do I setup this test using MockObject? I've tried this:

[Test, VerifyMocks]
public void TM_TestConfiguredInterface_ShouldLoad()
{
    var DTO = new AdjustmentCategoryDTO { CategoryID = 1 };
    var IDAL = RecorderManager.CreateMockedObject<AdjustmentCategoryData>(StrictFlags.AllMethods);
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
        recorder.MockAllInstances = true;
        recorder.ExpectAndReturn(IDAL.GetCategory(1), DTO);
    }

    var category = AdjustmentCategory.GetCategory(1);

    Assert.AreEqual(1, category.CategoryID);
    Assert.IsFalse(category.IsActive);
}


But I get null reference exceptions for other parts of the DAL. It seems like I need the equivalent for Members.ReturnRecursiveFakes, is there such a thing in NaturalMocks?

Is this possible or is my approach wrong?

Thanks,

Dave Erwin
asked by dave.erwin (1.3k points)

6 Answers

0 votes
Hi Dave

If you are using interface + DI you should inject your fake object into the class under test either by some DI framework or by sending it as an argument to the dependent class.
from the code you posted I can't understand where are using interface.
Can you please post the relevant code for AdjustmentCategory* classes and methods?

Having said that I want to add that the error message you got is misleading. It directed you to use the older API while you still can use the AAA API. It is a bug and we will fix it.
answered by ohad (35.4k points)
0 votes
This is the relevant StructureMap configuration:

public static class Configure
{
    public static void Dependencies()
    {
        StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;

        StructureMapConfiguration
            .BuildInstancesOf<TDA>()
            .TheDefaultIsConcreteType<TDADirect>();
     }
}


What I had in mind was that if the configuration was change the test would test whatever concrete class the configuration pointed to. Therefore I would need the unit test to reference the interface instead of a concrete class. Is there a way to do this with AAA?

This is the interface: (just working with a simple one to get this working)

public interface IAdjustmentCategoryData : IDisposable
{
    IAdjustmentCategoryDTO Add(IAdjustmentCategoryDTO dto);
    IAdjustmentCategoryDTO Update(IAdjustmentCategoryDTO dto);
    bool Delete(int categoryID);

    IAdjustmentCategoryDTO GetCategory(int categoryID);
    IEnumerable<IAdjustmentCategoryDTO> GetList(bool activeOnly);
}


This is the DTO interface (doesn't really matter but it might fill in some detail):

public interface IAdjustmentCategoryDTO
{
    int CategoryID { get; set; }
    string Name { get; set; }
    int ActiveFlag { get; set; }
    bool IsNew { get; set; }
    bool IsDeleted { get; set; }
}


This is just the data layer for a typical CRUD application. Using DI to eventually allow swapping in an nHibernate or other data access method.

Part of the question is does it make sense that I want to test this way? It seems like I am making the test less brittle by testing against whatever interface implementation is in place when the test is run. I'm just getting started so I may be all wet here.

Thanks,

Dave Erwin
answered by dave.erwin (1.3k points)
0 votes
What should the error message read? That might point me in the right direction.

Thanks,

Dave Erwin
answered by dave.erwin (1.3k points)
0 votes
Oops, forgot to show the test setup code.

[ SetUp ]
public void Setup()
{
    Configure.Dependencies();
}


Thanks,

Dave Erwin
answered by dave.erwin (1.3k points)
0 votes
Hi Dave

About the error message - The error message is wrong since you are using the AAA API and the error message directs you to the older API.

Roughly speaking,
The following code is doing the same thing i.e. creating a fake instance that implements the interface and then send it as an argument to a method that expects the interface as an argument:
// AAA API
var fake = Isolate.Fake.Instance<IMyInteFace>();
SomeClass someClass = new SomeClass();
someClass.Method(fake);

// Natural Mocks API
var mock = RecorderManager.CreateMockedObject<IMyInteFace>();
SomeClass someClass = new SomeClass();
someClass.Method(mock);


The code below is doing the same thing in both API's - faking the NEXT instance creation of a concrete type (next new)

// AAA API
var fake = Isolate.Fake.Instance<ConcreteClass>();
Isolate.Swap.NextInstance<ConcreteClass>().With(fake);

// This line will return a faked object!
ConcreteClass concreteClass = new ConcreteClass();


// Natural Mocks API
using (var recordExpectations = RecorderManager.StartRecording())
{
    ConcreteClass mock = new ConcreteClass();
}

// This line will return a faked object!
ConcreteClass concreteClass = new ConcreteClass();



About the problem:
From the message it looks like the Isolator 'see' AdjustmentCategoryData as an interface but from the code you posted I can see that it is a concrete class, so my question is where do you get the error? (what line).
answered by ohad (35.4k points)
0 votes
Hi Ohad,

The code I posted showed an example of the test setup for a concrete class that works. When I replace both occurrences of AdjustmentCategoryData with IAdjustmentCategoryData I get the "cannot type mock interfaces" error.

The error occurs on this line:

Isolate.Swap.NextInstance<IAdjustmentCategoryData>().With(dal);

I've actually been able to get around the problem by using Rhino.Mocks to generate a stub and then using StructureMap to inject the stub. I could probably use StructureMap to inject the TypeMock fake as well but it's just as easy with Rhino.Mocks. I was expecting Swap.NextInstance to do the same thing as StructureMaps ObjectFactory.InjectStub but the error gets in the way.

Just curious why it doesn't work.

Thanks,

Dave Erwin
answered by dave.erwin (1.3k points)
...