ServiceStack服务的单元测试

时间:2013-03-19 20:57:39

标签: unit-testing nunit moq servicestack

我正在尝试为ServiceStack服务编写简单的单元测试,我正在进行测试,他们已经在线并且很少有线程在这里。这是我想要完成的大部分细节的主线程 - Unit Test HTTPRequest Headers with ServiceStack

但是,我遇到了将IDbConnection对象注入服务的问题。在web方法中,使用OrmLite的GetDictionary方法填充字典对象。但是我无法模仿它,因为GetDictionary是扩展方法。

 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."}
    };
}

在测试方法

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

如果无法模拟GetDictionary方法,我甚至愿意调用点击DB的web方法,为此我需要创建AppHost。

1 个答案:

答案 0 :(得分:3)

我认为有几个选项需要研究。

  • 模拟/存根/单元测试扩展方法herehere或其他各种广告位。我不认为有一种首选的方法可以做到这一点,但有一些选项和框架/库可以提供帮助。

  • 运行内存数据库(如Sqlite)进行单元测试。请参阅here

  • 您可以将IDConnection抽象为CustomerLookUpRepository,并将CustomerLookUpRepository注入您的服务。然后你可以模拟你的'存储库'。

我试试这个'安排'。到目前为止,它似乎适用于大多数基本情况。数据访问模式来自Redis Web Service example。但是YMMV。

测试(使用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...  
    }

服务类 - 使用ISqlRepository抽象/隐藏IDbConnection。 ISqlRepository有一个函数,它将函数作为参数。函数签名(参数)将IDbConnection作为参数,因此我不必编写几种方法来访问数据库。

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);
        }
    }
}