Showing posts with label Unit Testing. Show all posts
Showing posts with label Unit Testing. Show all posts

Saturday, August 25, 2012

Eager-loading deep object graph from repository object

If your repository component don't have an abstraction layer for eager-loading deep object graph, your ORM will spill to your controller. Caveat: just detect the provider, so your MVC app is still unit-testing-friendly


public class SomeController : Controller
{
    const string EFIndicator = "System.Data.Entity.Internal.Linq.DbQueryProvider";

    IQueryable<Question> _q = null;

    public SomeController (IQueryable<Question> q)
    {
        _q = q;
    }
 
    public ViewResult ShowEverything(int id)
    {

        Question q = null;
        var q1 = _q.Where(x => x.QuestionId == id);


        if (_q.Provider.ToString() == EFIndicator)
        {
            var backToEf = (System.Data.Entity.Infrastructure.DbQuery<Question>)q1;

            q = backToEf
            .Include("AskedBy")
            .Include("QuestionModifiedBy")

            .Include("QuestionComments")

            .Include("Answers")
                .Include("Answers.AnswerComments")

            .Single();
        }

        return View(q);

    }

}


And you have to anticipate different eager-loading mechanism based on the IQueryable ORM provider too, e.g. NHibernate:


public ViewResult ShowEverything(int id)
{


    Question q = null;
    var q1 = _q.Where(x => x.QuestionId == id);



    if (_q.Provider.ToString() == EFIndicator)
    {

        var backToEf = (System.Data.Entity.Infrastructure.DbQuery<question>)q1;

        q = backToEf
        .Include("AskedBy")
        .Include("QuestionModifiedBy")

        .Include("QuestionComments")

        .Include("Answers")
            .Include("Answers.AnswerComments")

        .Single();

    }
    else if (_q.Provider is NHibernate.Linq.DefaultQueryProvider)
    {
        q1
        .FetchMany(x => x.QuestionComments)
        .ToFuture();


        q1
        .Fetch(x => x.AskedBy)
        .Fetch(x => x.QuestionModifiedBy)
        .FetchMany(x => x.Answers)
        .ToFuture();


        //sess.Query<answer>()
        //.Where(x => x.Question.QuestionId == id)
        //.FetchMany(x => x.AnswerComments)
        //.ToFuture();

        q = q1.ToFuture().Single();
    }
    else
    {
        // Repository pattern is unit-testing friendly code ツ
        q = q1.ToSingle();
    }


    return View(q);
   
}




You'll notice in the code above that we cannot eager-load NHibernate's AnswerComments. So you have to pass the Answer repository too. An argument can be made that NHibernate can leak repository abstractions. Following is the repository pattern-using code that supports NHibernate eager-loading mechanism. Though if you have a good dependency injection component, you don't have to worry about changes, laugh in the face of changes when you use empowering tools.


public class SomeController : Controller
{
     const string EFIndicator = "System.Data.Entity.Internal.Linq.DbQueryProvider";


     IQueryable<Question> _q = null;
     IQueryable<Answer> _a = null;

     public SomeController (IQueryable<Question> q, IQueryable<Answer> a)
     {
      _q = q;
      _a = a;
     }
     
    public ViewResult ShowEverything(int id)
    {

        Question q = null;
        var q1 = _q.Where(x => x.QuestionId == id);



        if (_q.Provider.ToString() == EFIndicator)
        {

            var backToEf = (System.Data.Entity.Infrastructure.DbQuery<Question>)q1;

            q = backToEf
                .Include("AskedBy")
                .Include("QuestionModifiedBy")

                .Include("QuestionComments")

                .Include("Answers")
                .Include("Answers.AnswerComments")


            .Single();

        }
        else if (_q.Provider is NHibernate.Linq.DefaultQueryProvider)
        {
            q1
            .FetchMany(x => x.QuestionComments)
            .ToFuture();


            q1
            .Fetch(x => x.AskedBy)
            .Fetch(x => x.QuestionModifiedBy)
            .FetchMany(x => x.Answers)
            .ToFuture();


            _a
            .Where(x => x.Question.QuestionId == id)
            .FetchMany(x => x.AnswerComments)
            .ToFuture();

            q = q1.ToFuture().Single();
        }
        else {} // Very unit-testing-friendly :-)

        q.QuestionText = q.QuestionText + "?";

        return View(q);

        }
    }


Sample unit test:
// Arrange
int id = 1;
string qt = "Answer to life and everything";

var questions = new List<Question> { new Question{ QuestionId = id, QuestionText = qt } }.AsQueryable();
var answers = new List<Answers> { new Answer{ Question = questions[0], AnswerText = "4" } }.AsQueryable();

// Act
Question q = (Question) new SomeController( questions, answers).ShowEverything(id);

// Assert
Assert.AreEqual(qt + "?", q.QuestionText);


Sample integration tests:
using (var db = new EfMapping())
{
        // Arrange
        int id = 1;

        IQueryable<Question> questions = db.Set<Question>();
        IQueryable<Answer> answers = db.Set<Answer>();

        Question qX = db.Set<Question>().Find(id);


        // Act
        Question q = (Question) new SomeController(questions, answers).ShowEverything(id);


        // Assert
        Assert.AreEqual(qX.QuestionText + "?", q.QuestionText);
}

/* for NHibernate:

using (var sess = NhMapping.GetSessionFactory().OpenSession())
{
        // Arrange
        int id = 1;

        IQueryable<Question> questions = sess.Query<Question>();
        IQueryable<Answer> answers = sess.Query<Answer>();

        Question qX = sess.Query<Question>().Load(id);


        // Act
        Question q = (Question) new SomeController(questions, answers).ShowEverything(id);


        // Assert
        Assert.AreEqual(qX.QuestionText + "?", q.QuestionText);
*/


Monday, February 27, 2012

A primer on unit testing with Moq

The following code is a primer on unit testing, just get Moq from Nuget. Note: Actual unit testing should be done on a separate project, not on Main method :-) This code just demonstrates how elegant Moq is for unit testing needs.

using System;

using Moq;

namespace MoqSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // ARRANGE
            
            decimal amount = 100;

            // that's why you will love unit testing, mishaps could be avoided :-)
            string errorMessage = "Could be an anomaly, passed amount is different from amount to transfer"; 

            var mockedSource = new Mock<IAccount>();
            mockedSource.Setup(x => x.Withdraw(It.Is<decimal>(a => a != amount))).Throws(new Exception(errorMessage));
            mockedSource.Setup(x => x.Deposit(It.Is<decimal>(a => a != amount))).Throws(new Exception(errorMessage));
            
            
            var mockedDest = new Mock<IAccount>();
            mockedDest.Setup(x => x.Withdraw(It.Is<decimal>(a => a != amount))).Throws(new Exception(errorMessage));
            mockedDest.Setup(x => x.Deposit(It.Is<decimal>(a => a != amount))).Throws(new Exception(errorMessage));
            



            // ACT

            int test = 0;
            /*
             * 0's error: NONE
             * 
             * 1's error:
             * Expected invocation on the mock should never have been performed, but was 1 times: source => source.Deposit(.amount)
             *  
             * 2's error:
             * Expected invocation on the mock once, but was 2 times: dest => dest.Deposit(.amount)
             * 
             * 3's error:
             * Expected invocation on the mock once, but was 0 times: dest => dest.Deposit(.amount)
             * 
             * 4's error:
             * Expected invocation on the mock once, but was 0 times: source => source.Withdraw(.amount)
             * 
             * 5's error:
             * Could be an anomaly, passed amount is different from transfer amount
             *             
             * */

            if (test == 0)
                TransactionMaker.TransferFund(mockedSource.Object, mockedDest.Object, amount);                
            else if (test == 1)
                TransactionMaker.TransferFundBuggy1(mockedSource.Object, mockedDest.Object, amount);                
            else if (test == 2)
                TransactionMaker.TransferFundBuggy2(mockedSource.Object, mockedDest.Object, amount);
            else if (test == 3)
                TransactionMaker.TransferFundBuggy3(mockedSource.Object, mockedDest.Object, amount);
            else if (test == 4)
                TransactionMaker.TransferFundBuggy4(mockedSource.Object, mockedDest.Object, amount);                
            else if (test == 5)
                TransactionMaker.TransferFundAnomalous(mockedSource.Object, mockedDest.Object, amount);                
            else
                throw new Exception("Select test case from 0 to 5");


            // ASSERT

            mockedSource.Verify(source => source.Withdraw(amount), Times.Once());
            mockedSource.Verify(source => source.Deposit(amount), Times.Never());

            mockedDest.Verify(dest => dest.Deposit(amount), Times.Once());
            mockedDest.Verify(dest => dest.Withdraw(amount), Times.Never());

        }

        
    }


    public static class TransactionMaker
    {

        public static void TransferFund(IAccount sourceAccount, IAccount destAccount, decimal amountToTransfer)
        {
            sourceAccount.Withdraw(amountToTransfer);
            destAccount.Deposit(amountToTransfer);            
        }

        public static void TransferFundBuggy1(IAccount sourceAccount, IAccount destAccount, decimal amountToTransfer)
        {
            sourceAccount.Withdraw(amountToTransfer);
            sourceAccount.Deposit(amountToTransfer);            
        }

        public static void TransferFundBuggy2(IAccount sourceAccount, IAccount destAccount, decimal amountToTransfer)
        {
            sourceAccount.Withdraw(amountToTransfer);
            destAccount.Deposit(amountToTransfer);
            destAccount.Deposit(amountToTransfer);
        }


        public static void TransferFundBuggy3(IAccount sourceAccount, IAccount destAccount, decimal amountToTransfer)
        {
            sourceAccount.Withdraw(amountToTransfer);            
        }

        public static void TransferFundBuggy4(IAccount sourceAccount, IAccount destAccount, decimal amountToTransfer)
        {
            sourceAccount.Deposit(amountToTransfer);
        }

        public static void TransferFundAnomalous(IAccount sourceAccount, IAccount destAccount, decimal amountToTransfer)
        {
            sourceAccount.Withdraw(amountToTransfer);
            destAccount.Deposit(amountToTransfer + 0.5M);
        }

        
    }



    public interface IAccount
    {
        void Withdraw(decimal v);
        void Deposit(decimal v);
    }

    public class Account : IAccount
    {
        public void Withdraw(decimal amount)
        {
        }

        public void Deposit(decimal amount)
        {
        }
    }
}

Monday, January 23, 2012

Liskov Substitution Principle, a simple example

The Liskov Substitution Principle of object oriented design states:

In class hierarchies, it should be possible to treat a specialized object as if it were a base class object.


using System;

namespace Liskov
{
 class Rectangle
 {    
  int _height;
  public virtual int Height
  {
   get{
    return _height;
   }
   set {
    _height = value;
   }
  }
  
  int _width;
  public virtual int Width
  {
   get {
    return _width;
   }
   set {
    _width = value;
   }   
  }
  
  public int Area
  {
   get {
    return _width * _height;
   }
  }
  
  
  public Rectangle (int width, int height)
  {
   Height = height;
   Width = width;
  }
  
 }
 
 
 class Square : Rectangle
 {
  public override int Height {
   set {
    base.Height = value;
    base.Width = value;
   }
  }
  
  public override int Width {
   set {
    base.Width = value;
    base.Height = value;
   }
  }
  

  public Square (int side) : base(width: side, height: side)
  {
  }
  
 }
 
 class MainClass
 {
  public static void Main (string[] args)
  {
   Rectangle s = new Square(side: 10);
   
   // 100, correct
   Console.WriteLine ("Area: {0}", s.Area); 
   
   // reusing the object r as rectangle object     
   s.Height = 4; 
   s.Width = 3;
   
   // expecting 12, actual output is 9. incorrect. Liskov Substitution Principle is violated
   Console.WriteLine ("Area: {0}", s.Area); 
  }
 }
}

The code above violates Liskov Substitution Principle, there should be no side effects on results even I use Square object for Rectangle purposes. Don't override properties just because it look smart to do so.

To set the Square's sides properly, set the two sides via one property only:

public int Side {
 get {
  return Height;
 }
 set {
  Height = Width = value;
 }
}



Tuesday, August 9, 2011

How to make your controller unit-testing friendly

There are some code that don't have anything to do with program's correctness, and could fail your unit test, and you need to conditionally suppress them. Case in point, you cannot apply eager loading on mocked IQueryable with NHibernate's FetchMany, you'll will encounter this error when you do so.

System.InvalidOperationException: There is no method 'FetchMany' on type 'NHibernate.Linq.EagerFetchingExtensionMethods' that matches the specified arguments

Don't do this:
public MovieController : Controller
{
    
    IRepository<Movie> _db;
    public MovieController(IRepository<Movie> db)
    {
        _db = db;
    }

    public ViewResult ShowMovieInfo(int id)
    {
        var query = 
                (from x in _db.All
                where x.MovieId == id 
                select x).FetchMany(x => x.Quotes);

        var movie = query.Single();
        return View(movie);
    }
}

When you perform unit testing on your controller, it will fail on FetchMany; NHibernate will throw an exception when the IQueryable(the All property of _db repository) didn't came from NHibernate, e.g. mocked IQueryable.

To make your controller unit testing-friendly, isolate and conditionally suppress anything that are not a factor on program correctness. NHibernate's FetchMany is one of those, even without FetchMany you can verify the program correctness. FetchMany is for performance optimization only.


Do this instead:

public MovieController : Controller
{
    
    IRepository<Movie> _db;
    public MovieController(IRepository<Movie> db)
    {
        _db = db;
    }

    public ViewResult ShowMovieInfo(int id)
    {
        var query = 
                from x in _db.All
                where x.MovieId == id 
                select x;

        if (query.Provider.GetType() == typeof(NHibernate.Linq.NhQueryProvider))
            query = query.FetchMany(x => x.Quotes);

        var movie = query.Single();
        return View(movie);
    }
}


Note: On NHibernate 3.2, there's no more NhQueryProvider, it's replaced with DefaultQueryProvider

Monday, August 8, 2011

NHibernate is testable too

On my last post regarding Entity Framework is infinitely testable, we can also do that on NHibernate too. We just need to suppress NHibernate from performing its fetching function when the provider of the given IQueryable is not of NHibernate type.

This is the code to accomplish that:

public static class UnitTestFriendlyNhFetching
{
    public static IQueryable<TOriginating> NhxFetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector)        
    {
        // Prior to NHibernate 3.2, use NhQueryProvider
        // (query.Provider is NHibernate.Linq.NhQueryProvider)

        if (query.Provider is NHibernate.Linq.DefaultQueryProvider)
            return query.Fetch(relatedObjectSelector);
        else
            return query;
    }

    
    public static IQueryable<TOriginating> NhxFetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector)
    {
        // Prior to NHibernate 3.2, use NhQueryProvider
        // (query.Provider is NHibernate.Linq.NhQueryProvider)

        if (query.Provider is NHibernate.Linq.DefaultQueryProvider)
            return query.FetchMany(relatedObjectSelector);
        else
            return query;
    }
}


Example use:

public class MovieController : Controller
{
    IRepository<Movie> _rm = null;
 
    public HomeController(IRepository<Movie> rm)
    {            
        _rm = rm;
    }
 
    public ViewResult Index()
    {        
        // NHibernate NhxFetchMany won't complain even if _rm.All came from mocked IQueryable only
        return View(_rm.All.Where(x => x.Title == "Thor")
            .NhxFetchMany(x=> x.Quotes));    
    }    
}

This is the repository interface
public interface IRepository<Ent> where Ent : class
{
    IQueryable<Ent> All { get; }
    void Save(Ent ent, byte[] version);
    void VersionedDelete(object id, byte[] version);
    Ent LoadStub(object id);
 
    string PrimaryKeyName { get; set; }
    string VersionName { get; set; }
}

The code above can work on aggregate root only, i.e. it can only fetch the children and parent of a given aggregate root, but it cannot further fetch the grandchildren of an aggregate root; ThenFetch and ThenFetchMany can only be chained after Fetch and FetchMany.

If we can find how to cast IQueryable to NHibernate's INhFetchRequest<TOriginating, TRelated>, then we can include unit testing-friendly extension methods for grandchildren entities

Wednesday, December 29, 2010

Fluent NHibernate AddFromNamespaceOf. The overlooked method of Fluent NHibernate

Unless I'm missing something, writing AddFromNamespaceOf method is a simple undertaking

public static class Helper
{

    public static FluentMappingsContainer AddFromNamespaceOf<T>(
           this FluentMappingsContainer fmc)
    {
        Type t = typeof(T);
        string ns = t.Namespace;
        
    
        var y = from x in t.Assembly.GetTypes()
                where 
                    x.FullName == ns + "." + x.Name
                    && x.BaseType.IsGenericType                        
                    && x.BaseType.GetGenericTypeDefinition().IsDerivedFrom(typeof(ClassMap<>))
                select x;
                
        foreach(Type z in y)
            fmc.Add(z);                 
    
        
        return fmc;
    }
    
    private static bool IsDerivedFrom(this Type givenType, Type genericType)
    {
        if (givenType == genericType)
            return true;
        
        if (givenType.BaseType.IsGenericType)
            return givenType.BaseType
                .GetGenericTypeDefinition().IsDerivedFrom(genericType);
        
        return false;
    }
}  

Useful when doing unit tests or other kind of testing and don't want to be bothered with creating separate projects/assembly for group of entities. Example: http://code.google.com/p/fluent-nhibernate-lowercase-system/source/browse/#svn

Friday, December 3, 2010

Unix transport error when unit testing NHibernate for Postgresql under Mono

If you happen to encounter the following error while doing unit testing for NHibernate for Postgresql under Mono...

Internal error
        RemotingException: Unix transport error.

...Change your Npgsql version to a Mono one, then that error won't happen.

That error will appear on unit testing if you are using MS .NET version of Npgsql (example: http://pgfoundry.org/frs/download.php/2868/Npgsql2.0.11-bin-ms.net4.0.zip) under Mono. When unit testing under Mono, you must use Mono version of Npgsql (example: http://pgfoundry.org/frs/download.php/2860/Npgsql2.0.11-bin-mono2.0.zip)

Weird problem, the error only appear when the code is run under Unit Testing(built-in in MonoDevelop). But when run independently, MS .NET version of Npgsql will run just fine under Mono. Anyway, to make matters simple, use Mono version of the component if you are building Mono stuff