4
votes

I am trying to write simple unit test for ServiceStack service, I am going through tests they've online and few threads here. This is the main thread that has most details I am trying to accomplish - Unit Test HTTPRequest Headers with ServiceStack.

However, I am facing problems injecting IDbConnection object into the service. In the webmethod, a dictionary object is populated by using OrmLite's GetDictionary method. But I am unable to mock it since GetDictionary is extension method.

 private Mock<IDbConnection> _dbConnectionMock;
 private Dictionary<string, string> _nameValuePairs;

 [SetUp]
 public void SetUp()
 {
    _dbConnectionMock = new Mock<IDbConnection>();

    _nameValuePairs = new Dictionary<string, string>()
    {
            {"name","test"},
            {"Updatedby",   "5/23/12 7:00:15 AM"},
            {"Address", "212 Adam St."}
    };
}

In test method

 var service = new CustomerLookupService(_dbConnectionMock.Object);
 var response = (HttpResult)service.Any(new CustomerLookup { name = "test" });
 //assert statements

If GetDictionary method cannot be mocked, I am even willing to call web method that hits DB, for this do I need to create AppHost.

1

1 Answers

3
votes

I think there are a couple of options to look into.

  • Mocking/stubbing/unit-testing extension methods here, here or various other spots. I don't think there is a preferred way to do this but there are some options and frameworks/libraries to help.

  • Running an in memory database such as Sqlite for your unit tests. See here.

  • You could abstract the IDConnection into a CustomerLookUpRepository and inject your CustomerLookUpRepository into your service. Then you can just mock your 'Repository'.

I've given this 'arrangement' a try. So far it seems to work for most basic cases. The data access pattern is taking from the Redis Web Service example. YMMV, though.

Test (using RhinoMocks)

    public void SomeTest()
    {
        var _nameValuePairs = new Dictionary<string, string>()
        {
            {"name","test"},
            {"Updatedby",   "5/23/12 7:00:15 AM"},
            {"Address", "212 Adam St."}
        };

        var mockSqlRepository = MockRepository.GenerateMock<ISqlRepository>();
        mockSqlRepository.Stub(
            x => x.Exec(Arg<Func<IDbConnection, Dictionary<string, string>>>.Is.NotNull)).Return(_nameValuePairs);

        var service = new CustomerLookupService { SqlRepository = mockSqlRepository }
        //MORE TEST CODE...  
    }

Service class - using ISqlRepository to abstract/hide IDbConnection. ISqlRepository has a function that takes a function as the parameter. The function signature (of the parameter) takes IDbConnection as a parameter so I don't have to write several methods to access the database.

public class CustomerLookupService
{
    public ISqlRepository SqlRepository { get; set; }

    public void Any(CustomerLookup request)
    {
        var results =
            SqlExec<Dictionary<string, string>>((con) => con.GetDictionary<type, type>("Select id, name from table"));
        //MORE SERVICE CODE
    }

    public T SqlExec<T>(Func<IDbConnection, T> fn)
    {
        return SqlRepository.Exec(fn);
    }
}

ISqlRepository

public interface ISqlRepository
{
    T Exec<T>(Func<IDbConnection, T> fn);
}

SqlRepository

public class SqlRepository : ISqlRepository
{
    public IDbConnectionFactory DbFactory { get; set; }

    public T Exec<T>(Func<IDbConnection, T> fn)
    {
        using (var con = DbFactory.OpenDbConnection())
        {
            return fn(con);
        }
    }
}