Testing NHibernate, Mocking ISession

472 views
Skip to first unread message

Troy T.

unread,
Jan 15, 2009, 2:23:40 PM1/15/09
to nhusers
Hi,
I'm using Linq to NH in a project, and would like to test my
repository code without hitting the database. I have code in my
repository as:

public class Repository : IRepository
{
(... code snipped for brevity ...)

public T FindBy<T>(Expression<Func<T, bool>> where)
{
return _session.Linq<T>().Where(where).FirstOrDefault();
}

}

Where _session is injected into the repository class as ISession.
Does anyone have some ideas on how to test this repository query code
without hitting the database? I'm using Rhinomocks for mocking.

My idea is to create a List<T> of Customer objects in the unit test
code (my test data), and mock out ISession and have it return that
test data when .Linq<T> is called on the session. To do that I've
started creating my own test stub that implements IQueryable that
would be responsible for returning the test data, but I'm having
trouble making that work.

So, just wondering if anyone could suggest a better path to accomplish
this? Or am I on the correct path?

Thanks!
Troy

John Teague

unread,
Jan 15, 2009, 3:22:18 PM1/15/09
to nhu...@googlegroups.com
Are you testing business logic that is using your repository, or are you testing the repository itself?

Troy Tuttle

unread,
Jan 15, 2009, 3:32:14 PM1/15/09
to nhu...@googlegroups.com
Both actually.  I specifically want to test querying logic like this:

public Customer FindByCustomerNumber(string customerNumber)
{
    return _repository.FindBy<Customer>(b => b.CustomerNumber == customerNumber);
}

Which calls....


public T FindBy<T>(Expression<Func<T, bool>> where)

     return Session.Linq<T>().Where(where).FirstOrDefault();
}

None of that code has any database concerns, just querying, so I would like to test it by mocking away the DB / NH Session. 

For integration testing, we would like to use the PersistenceSpecification utility...

new PersistenceSpecification<Customer>(Session)
     .CheckProperty(x => x.FirstName, "Dude")
     .VerifyTheMappings();

Does that make sense?  With Linq to NH, it seems like we should be able to test our querying logic without doing heavy and messy integration work.

Thanks!
Troy

isaiah perumalla

unread,
Jan 15, 2009, 3:47:25 PM1/15/09
to nhusers
In my experience, i found it useful to simply write integration-tests
to test the repositories.
I generally avoid mocking 3rd party type such as ISession since the
interaction tests will most like be quite fragile

On Jan 15, 1:22 pm, "John Teague" <jctea...@gmail.com> wrote:
> Are you testing business logic that is using your repository, or are you
> testing the repository itself?
>

Troy Tuttle

unread,
Jan 15, 2009, 4:29:31 PM1/15/09
to nhu...@googlegroups.com
That's what we are currently doing now, but as the domain model grows, the integration tests can get huge when testing queries with multiple criteria (like a search screen).  I'm finding most of the work is in getting the database in the correct state for these kinds of respository/integration testing.  So, my thought is, just test the integration by using PersistenceSpecification.VerifyTheMappings(), and test the queries in isolation (mocked). It's a lot easier to create an in-memory list of customers to query against than setup records in the db.

Thanks for the feedback though.

tt

Roger Kratz

unread,
Jan 15, 2009, 5:36:45 PM1/15/09
to nhu...@googlegroups.com
<<It's a lot easier to create an in-memory list of customers to query against than setup records in the db.>>
Why? Maybe I'm missing something but...
inMemList.Add() vs repository.Add() is pretty similar?


________________________________
Från: nhu...@googlegroups.com [nhu...@googlegroups.com] för Troy Tuttle [troyl...@gmail.com]
Skickat: den 15 januari 2009 22:29
Till: nhu...@googlegroups.com
Ämne: [nhusers] Re: Testing NHibernate, Mocking ISession

That's what we are currently doing now, but as the domain model grows, the integration tests can get huge when testing queries with multiple criteria (like a search screen). I'm finding most of the work is in getting the database in the correct state for these kinds of respository/integration testing. So, my thought is, just test the integration by using PersistenceSpecification.VerifyTheMappings(), and test the queries in isolation (mocked). It's a lot easier to create an in-memory list of customers to query against than setup records in the db.

Thanks for the feedback though.

tt

On Thu, Jan 15, 2009 at 2:47 PM, isaiah perumalla <isaiahp...@googlemail.com<mailto:isaiahp...@googlemail.com>> wrote:

In my experience, i found it useful to simply write integration-tests
to test the repositories.
I generally avoid mocking 3rd party type such as ISession since the
interaction tests will most like be quite fragile

On Jan 15, 1:22 pm, "John Teague" <jctea...@gmail.com<mailto:jctea...@gmail.com>> wrote:
> Are you testing business logic that is using your repository, or are you
> testing the repository itself?
>

Stefan Sedich

unread,
Jan 15, 2009, 6:06:37 PM1/15/09
to nhu...@googlegroups.com
My 2 cents if that counts :)


Personally I have gone down this route before with testing
repositories, but in the end found that mocking session calls just
becomes WAY too hard. I guess you ask yourself what value do you get
from mocking your queries against the session?

IMO this is very little value, I get a lot more by actually making
these an integration test against my database. Now this does 2 things
for me, it verifies that my mapping files are correct and it tests my
repository code. So we see here that doing a test like this has a
greater return on my effort.

The other thing if you use something like NDBUnit, you can make these
tests better, we are able to put our database into a consistent state
at the start of each test run, and by using something like SQLite as
an in memory database we are able to make these tests quick to run.


This is just the conclusion I came to after writing many fragile tests
mocking session calls. But as I say have a look at NDBUnit, and in
particular if you wan't to see how it is done have a watch through the
Summer of NHibernate screen casts as this is shown there.



Cheers
Stefan
--
Stefan Sedich
Software Developer
http://weblogs.asp.net/stefansedich

isaiah perumalla

unread,
Jan 15, 2009, 6:07:19 PM1/15/09
to nhusers
did you try out nDBUnit to get the db in a good state for tests ?



On Jan 15, 2:29 pm, "Troy Tuttle" <troyltut...@gmail.com> wrote:
> That's what we are currently doing now, but as the domain model grows, the
> integration tests can get huge when testing queries with multiple criteria
> (like a search screen). I'm finding most of the work is in getting the
> database in the correct state for these kinds of respository/integration
> testing. So, my thought is, just test the integration by using
> PersistenceSpecification.VerifyTheMappings(), and test the queries in
> isolation (mocked). It's a lot easier to create an in-memory list of
> customers to query against than setup records in the db.
>
> Thanks for the feedback though.
>
> tt
>
> On Thu, Jan 15, 2009 at 2:47 PM, isaiah perumalla <
>

Troy Tuttle

unread,
Jan 15, 2009, 8:31:40 PM1/15/09
to nhu...@googlegroups.com
Yes, by itself it is very similar.  But when we get to a full suite of integration tests, I have to manage cleanup so the db is in a good state before the next test runs.  But an in-memory collection will be cleaned up for me automatically by the garbage collector (or at least I don't have to worry about it). 

Stefan Sedich

unread,
Jan 15, 2009, 8:36:23 PM1/15/09
to nhu...@googlegroups.com
How is this testing your queries though? How is an in memory
collection going to mimic your relational DB and validate your mapping
files are correct? Cascades work etc etc.

I still think NDBUnit is the way to go when testing your repository layer.



Cheers
Stefan

Roger Kratz

unread,
Jan 16, 2009, 4:06:54 AM1/16/09
to nhu...@googlegroups.com

There are many different approaches for this, I prefer (I’m using naked nunit, don’t know much about nDbUnit)…

* Create the db-schema (and some must-have-data in db) in setupfixture, using SchemaExport

* Run every test in a tran that’s rollbacked after the test

Works in 95% of the cases for me.

Troy Tuttle

unread,
Jan 16, 2009, 10:46:36 AM1/16/09
to nhu...@googlegroups.com
I've heard others using the transaction approach as well.  It would definitely help streamline the setup/teardown code. 

Thanks.

isaiah perumalla

unread,
Jan 16, 2009, 11:23:40 AM1/16/09
to nhusers
be careful though with the transaction roll back approach, it can hide
some subtle bugs, which may only be found by committing to a db. I
seen a project where they had a all their repositories tested by
executing queries and then rolling back the transaction, but when they
went to production there were quite a few bugs. In the end they had to
write integration tests to flush these out.
IMO at some point you still need to test the integration/functional
parts, to ensure things are working, and there is little benefit in
testing the queries alone

On Jan 16, 8:46 am, "Troy Tuttle" <troyltut...@gmail.com> wrote:
> I've heard others using the transaction approach as well. It would
> definitely help streamline the setup/teardown code.
>
> Thanks.
>
> On Fri, Jan 16, 2009 at 3:06 AM, Roger Kratz <Roger.Kr...@teleopti.com>wrote:
>
> > There are many different approaches for this, I prefer (I'm using naked
> > nunit, don't know much about nDbUnit)…
>
> > * Create the db-schema (and some must-have-data in db) in setupfixture,
> > using SchemaExport
>
> > * Run every test in a tran that's rollbacked after the test
>
> > Works in 95% of the cases for me.
>
> > *From:* nhu...@googlegroups.com [mailto:nhu...@googlegroups.com] *On
> > Behalf Of *Troy Tuttle
> > *Sent:* den 16 januari 2009 02:32
> > *To:* nhu...@googlegroups.com
> > *Subject:* [nhusers] Re: Testing NHibernate, Mocking ISession
>
> > Yes, by itself it is very similar. But when we get to a full suite of
> > integration tests, I have to manage cleanup so the db is in a good state
> > before the next test runs. But an in-memory collection will be cleaned up
> > for me automatically by the garbage collector (or at least I don't have to
> > worry about it).
>
> > On Thu, Jan 15, 2009 at 4:36 PM, Roger Kratz <Roger.Kr...@teleopti.com>
> > wrote:
>
> > <<It's a lot easier to create an in-memory list of customers to query
> > against than setup records in the db.>>
>
> > Why? Maybe I'm missing something but...
> > inMemList.Add() vs repository.Add() is pretty similar?
>
> > ________________________________
> > Från: nhu...@googlegroups.com [nhu...@googlegroups.com] för Troy Tuttle
> > [troyltut...@gmail.com]
> > Skickat: den 15 januari 2009 22:29
> > Till: nhu...@googlegroups.com
> > Ämne: [nhusers] Re: Testing NHibernate, Mocking ISession
>
> > That's what we are currently doing now, but as the domain model grows, the
> > integration tests can get huge when testing queries with multiple criteria
> > (like a search screen). I'm finding most of the work is in getting the
> > database in the correct state for these kinds of respository/integration
> > testing. So, my thought is, just test the integration by using
> > PersistenceSpecification.VerifyTheMappings(), and test the queries in
> > isolation (mocked). It's a lot easier to create an in-memory list of
> > customers to query against than setup records in the db.
>
> > Thanks for the feedback though.
>
> > tt
>
> > On Thu, Jan 15, 2009 at 2:47 PM, isaiah perumalla <
> > isaiahperuma...@googlemail.com<mailto:isaiahperuma...@googlemail.com>>

Troy Tuttle

unread,
Jan 16, 2009, 11:24:34 AM1/16/09
to nhu...@googlegroups.com
I agree that testing the mapping is very important.  My goal has been to test my querying logic separate from the mapping so I can leverage PersistenceSpecification (from FluentNHibernate.Framework) utility to do mapping tests. 

A developer on Stackverflow.com had a good idea: 
http://stackoverflow.com/questions/448405/nhibernate-testing-mocking-isession#448775

His approach of exposing IQueryable is really what I was looking for.  I don't have to implement IQueryable myself.  And my repository/mapping code gets reduced to:

        [Test]
        public void Should_get_customer_by_customer_number4()
        {
            var repository = MockRepository.GenerateStub<IRepository>();
          
            repository.Expect(x => x.FindBy<Customer>())
                .Return(_customers.AsQueryable());

            Customer actualCustomer = _custRepository.FindByCustomerNumber("100313");
            Assert.... code here
        }

Where _customers is my list of test data in a IList<T>.  And my mapping (integration) tests look like:

        [Test]
        public void Should_persist_Customer_to_db_and_read_back()
        {
            new PersistenceSpecification<Customer>(Session)
                .CheckProperty(x => x.CustomerNumber, "11111")
                .CheckProperty(x => x.Name, "Jones Inc.")
                .VerifyTheMappings();
        }

For my team, I think this approach will mean elimination of a ton of setup/teardown test code.  And it appeals to my Seperation of Concerns sensibilities.  Isn't the whole point of LINQ and LINQNHibernate to have a consistent query language/mechanism?  If I do a good job of seperating the concerns of my repositories, mappings, and NH itself, then my query code in my repository should have no knowledge of SQL or relational database structures.  It should be concerned with filtering or querying a list of objects for the domain.  So why not arrange the test code in the same way (seperating concerns)? 

I do want to look at NDBUnit though, so thanks for the tip and the other feedback!

Troy

Luke Bakken

unread,
Jan 16, 2009, 11:34:04 AM1/16/09
to nhu...@googlegroups.com
> be careful though with the transaction roll back approach, it can hide
> some subtle bugs, which may only be found by committing to a db. I
> seen a project where they had a all their repositories tested by
> executing queries and then rolling back the transaction, but when they
> went to production there were quite a few bugs. In the end they had to
> write integration tests to flush these out.
> IMO at some point you still need to test the integration/functional
> parts, to ensure things are working, and there is little benefit in
> testing the queries alone

I second this - I have found that you must actually commit and go to
another session to ensure that your code is correct. Rollback hides
bugs.

Reply all
Reply to author
Forward
0 new messages