1

I have a class like below where using Fluent Nhibernate I am getting data from database

public class MyActualClass
{
    public MyActualClass(ISessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    public List<AnnualInformation> GetData()
    {
        using (session = sessionFactory.OpenSession())  
        {  
            var result = session.QueryOver<AnnualInformation>() 
                         .SelectList(list => list  
                                     .Select(x => x.Id)  
                                     .Select(x => x.CreationDate)  
                                     .Select(x => x.AnnualAmount)  
                                     .Select(x => x.AnnualCurrency)  
                                     .Select(() => monthlyAlias.MonthlyAmount)  
                                     .Select(() => monthlyAlias.MonthlyCurrency)  
                                     .Select(() => shareAlias.CurrentSharevalue)  
                                     .Select(() => miscAlias.MarketValueAmount)  
                                     ).Where(a => a.Id == 123456).List<AnnualInformation>();  
        }
    }
} 

I Have written unit test case for above method like below

public class MyTestClass
{
    private static ISessionFactory sessionFactory;
    private static ISession session;

    public MyTestClass()
    {
        sessionFactory = A.Fake<ISessionFactory>();
        session = A.Fake<ISession>();

        A.CallTo(() => sessionFactory.OpenSession()).Returns(session);
    }

    [Fact]
    public void MyTest()
    {
        var annualDetails = 
                new AnnualInformation
                {
                    Id= 1,
                    AnnualCurrency= "string",
                    AnnualAmount= "Example"
                }
         var listOfAnnualInformation=
            new List<AnnualInformation>
            {
                annualDetails 
            };  

        A.CallTo(session.QueryOver<AnnualInformation>()).WithReturnType<IList<AnnualInformation>>().Returns(listOfAnnualInformation);
        var myInstance = new MyActualClass(sessionFactory);
        myInstance.GetData();
    }
}  

Actually if you see below code

session.QueryOver() .SelectList(...

will return "result" in method GetData(). After that I am manipulating "result" datastructure to get Id, CreationDate, AnnualAmount, AnnualCurrency
Therefore it is very important that some value is returned from "result". My problem is the count of resulty is always 0.

I want the below line of code

A.CallTo(session.QueryOver()).WithReturnType>().Returns(listOfAnnualInformation);

to return a list with atleast one element. Now i believe i clarified my requirements

Please suggest what should be done here ?

1 Answers1

2

Based on the new code (which still doesn't quite compile - missing ;, result isn't returned from GetData, and if it were, the return type of GetData should be IList<AnnualInformation>, but with those changes I was able to get a test to run) I can offer some commentary:

A.CallTo(session.QueryOver<AnnualInformation>()).WithReturnType<IList<AnnualInformation>>()
    .Returns(listOfAnnualInformation);

Configures the object that comes back from calling session.QueryOver<AnnualInformation>(). (Note there's no lambda here, so this line actually calls QueryOver.)
session is a Fake, and so when you call QueryOver<AnnualInformation>() on this line, it will return a new Fake IQueryOver. The "WithReturnType…Returns…" configures the new Fake IQueryOver to return listOfAnnualInformation when any method that returns a IList<AnnualInformation> is called.

However, when Fakes' methods are called, unless they've been configured to do something different, they return a new object. So inside GetData when you call QueryOver, you get a different fake IQueryOver, which has not been configured at all. That's one problem.

Second problem: the call to SelectList will return yet another faked IQueryOver.

We can work around all these things:

var aFakeQueryOver = A.Fake<IQueryOver<AnnualInformation, AnnualInformation>>();
A.CallTo(aFakeQueryOver).WithReturnType<IQueryOver<AnnualInformation, AnnualInformation>>()
    .Returns(aFakeQueryOver);
A.CallTo(aFakeQueryOver).WithReturnType<IList<AnnualInformation>>()
    .Returns(listOfAnnualInformation);

A.CallTo((() => session.QueryOver<AnnualInformation>())).Returns(aFakeQueryOver);

And now the faking behaves as we want. However, all we've done is short-circuit all the logic in GetData, except to see that it uses the sessionFactory to open a session, and then QueryOver on that session. SelectList and Where and List have all been bypassed.

My usual advice in this situation is to make your data access layer as thin as possible and to integration test it. Alternatively, I've seen people suggest having NHibernate use an in-memory MySql database. Still an integration test of sorts, but at least it's more isolated.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • Yes you are right the call should be A.CallTo(() => session.QueryOver()).Returns(listOfAnnualInformation); But even if i keep that, I am not getting any return value which i mentioned. listOfAnnualInformation in GetData always appears with 0 records after Queryover Call. Not sure what is happening – The mentalist Coder Dec 02 '15 at 09:12
  • I added your code to a test project and started using FluentNHibernate to see if I could figure out your problem, but the test code you provided doesn't even compile (for starters, missing `;` after you declare `annualDetails`). Nor can I tell what type `listOfAnnualInformation` is - it can't be a `List`, as the return type of `QueryOver` is a `QueryOver`. Could you fill in these missing details and provide a compiling failing test that we could work with? (Even after that, there are a lot of other QueryOver calls, so in the end we may just implement a facsimile of QueryOver…) – Blair Conrad Dec 02 '15 at 12:03
  • I have updated the code with incorporating your suggestions. Please refer above – The mentalist Coder Dec 02 '15 at 13:13
  • Thanks Blair, definitely a deserving +1 for the kind of effort you have put in. however I will try it and then will get back to you on my success :) – The mentalist Coder Dec 02 '15 at 20:51
  • Ha, thanks. It may just be that the types and methods involved are not amenable to this style of testing, but I'm here to help with whatever fiddly FakeItEasy bits I can. – Blair Conrad Dec 02 '15 at 21:26