views:

121

answers:

2

I have tried to use Moq to unit test a method on a repository that uses the DetachedCriteria class. But I come up against a problem whereby I cannot actually mock the internal Criteria object that is built inside. Is there any way to mock detached criteria?

Test Method

        [Test]
        [Category("UnitTest")]
        public void FindByNameSuccessTest()
        {          
            //Mock hibernate here
            var sessionMock = new Mock<ISession>();
            var sessionManager = new Mock<ISessionManager>();
            var queryMock = new Mock<IQuery>();
            var criteria = new Mock<ICriteria>();
            var sessionIMock = new Mock<NHibernate.Engine.ISessionImplementor>();

            var expectedRestriction = new Restriction {Id = 1, Name="Test"};

            //Set up expected returns
            sessionManager.Setup(m => m.OpenSession()).Returns(sessionMock.Object);
            sessionMock.Setup(x => x.GetSessionImplementation()).Returns(sessionIMock.Object);

            queryMock.Setup(x => x.UniqueResult<SopRestriction>()).Returns(expectedRestriction);

            criteria.Setup(x => x.UniqueResult()).Returns(expectedRestriction);

            //Build repository            
            var rep = new TestRepository(sessionManager.Object);

            //Call repostitory here to get list
            var returnR = rep.FindByName("Test");


            Assert.That(returnR.Id == expectedRestriction.Id);
        }

Repository Class

public class TestRepository
{
    protected readonly ISessionManager SessionManager;

    public virtual ISession Session
    {
        get { return SessionManager.OpenSession(); }
    }

    public TestRepository(ISessionManager sessionManager)
    {
    }


    public SopRestriction FindByName(string name)
    {

        var criteria = DetachedCriteria.For<Restriction>().Add<Restriction>(x => x.Name == name)
        return criteria.GetExecutableCriteria(Session).UniqueResult<T>();
    }

}

Note I am using "NHibernate.LambdaExtensions" and "Castle.Facilities.NHibernateIntegration" here as well. Any help would be gratefully appreciated.

Essentially I am getting a null reference exception on the assert of the object returned. Thus I assume that I have not connected up the criteria correctly. But I don't think I can do this because the criteria is a private field of the Detached Criteria which is created inside my repository!

+4  A: 

Honestly I gave up on trying to unit test anything that touches the database a long time ago.

It's so much easier to spin up an in memory Sqlite db and just run the actual tests. Or if you would rather run them against the real database then just move them into your integration tests that only get ran when you do a checkin to source control.

ShaneC
I'm not talking about touching the database. I am testing the repository classes. Making sure they actually access the correct methods. I do mapping tests separately with Sqlite. I think you misunderstood my question. I was mocking out nhibernate not testing the actual database itself.
Aim Kai
I agree with what you are saying but its not the answer to the question.
Aim Kai
But why mock out NHibernate? Why not just hit the real database? You should be careful about focusing too much on how something is done which leads to over specification test smells. What you should be worried about is do I get the expected results when I use my repository.
ShaneC
+1  A: 

I think you're missing the point of using mocking in this situtation. What you want to mock is the method

public SopRestriction FindByName(string name)
{
    ...
}

So then you can return any type of SopRestriction you want and not worry about the fact it's querying NHibernate.

It's pointless to ever mock any type of datacontext because you'll never gain any value.

The easiest way to do this would be to extract an interface from TestRepository so like ITestRepository and then make the rest of your dependency graph dependent on ITestRepository and you can mock the repository itself easily in your unit tests.

Follow up: Regarding your response about wanting to verify method calls inside your repository what I would reccomend is wrapping all of the NHibernate specific usage into methods themselves that don't have any type of parameter or return that is NHibernate specific so then you can mock those methods and just expect them to work. This is why unit testing is less valuable at this stage because you don't gain much. With what you said I wouldn't mock them at all but would make them full "integration" tests that touch the database or do what they need to do. I still consider these to be unit tests even if TDD purists would say they're integration tests.

Chris Marisic
Sure I can mock a service or another patterned class which has a property that instantiates the ITestRepository. However I want to test the SopRepository to see if certain methods were called not to actually retrieve a value. So I think you are also answering another question as well.
Aim Kai