servicestack,Unit Testing,Nunit,Moq,servicestack" /> servicestack,Unit Testing,Nunit,Moq,servicestack" />

Unit testing ServiceStack服务的单元测试

Unit testing ServiceStack服务的单元测试,unit-testing,nunit,moq,servicestack,Unit Testing,Nunit,Moq,servicestack,我正在尝试为ServiceStack服务编写简单的单元测试,我正在经历他们在线的测试和这里很少的线程。这是我试图完成的最详细的主线- 但是,我在将IDbConnection对象注入服务时遇到了问题。在webmethod中,使用OrmLite的GetDictionary方法填充dictionary对象。但我无法模拟它,因为GetDictionary是扩展方法 private Mock<IDbConnection> _dbConnectionMock; private Diction

我正在尝试为ServiceStack服务编写简单的单元测试,我正在经历他们在线的测试和这里很少的线程。这是我试图完成的最详细的主线-

但是,我在将IDbConnection对象注入服务时遇到了问题。在webmethod中,使用OrmLite的GetDictionary方法填充dictionary对象。但我无法模拟它,因为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."}
    };
}

如果GetDictionary方法不能被模仿,我甚至愿意调用命中DB的web方法,为此我需要创建AppHost。

我认为有几个选项可以研究

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

  • 为单元测试运行内存中的数据库,如Sqlite。看

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

我已经尝试过这种“安排”。到目前为止,它似乎适用于大多数基本情况。数据访问模式取自。YMMV,不过

测试(使用Rhinomock)

public void SomeTest()
{
var_nameValuePairs=新字典()
{
{“名称”,“测试”},
{“更新人”,“5/23/12 7:00:15 AM”},
{“地址”,“亚当街212号”}
};
var mockSqlRepository=MockRepository.GenerateMock();
mockSqlRepository.Stub(
x=>x.Exec(Arg.Is.NotNull)).Return(_nameValuePairs);
var service=new CustomerLookupService{SqlRepository=mockSqlRepository}
//更多测试代码。。。
}
服务类-使用ISqlRepository抽象/隐藏IDB连接。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);
    }
}
公共类CustomerLookupService
{
公共ISqlRepository SqlRepository{get;set;}
公共作废任何(CustomerLookup请求)
{
var结果=
SqlExec((con)=>con.GetDictionary(“从表中选择id、名称”);
//更多服务代码
}
公共T SqlExec(功能fn)
{
返回SqlRepository.Exec(fn);
}
}
ISqlRepository

public interface ISqlRepository
{
    T Exec<T>(Func<IDbConnection, T> fn);
}
公共接口isql存储库
{
T执行官(职能部门和职能部门);
}
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);
        }
    }
}
公共类SqlRepository:ISqlRepository { 公共IDbConnectionFactory数据库工厂{get;set;} 公共T执行官(职能fn) { 使用(var con=DbFactory.OpenDbConnection()) { 返回fn(con); } } }
它就像一个符咒。我怀疑,如果我们有多个读取操作在方法中检索字典,那么如何在测试中模拟这些字典。我们是否需要以相同的顺序提及模拟对象。如果您正在测试一个将执行许多数据库操作且每个操作返回相同类型的方法,那么此解决方案可能不是最好的。可能能够使用Rhino Mocks实现基于“调用顺序”的不同返回值-感谢您的回复。您知道关于多个数据库操作的其他想法吗。我喜欢这种方法的事实是,我不需要违反DRY原则来创建单独的存储库。
public interface ISqlRepository
{
    T Exec<T>(Func<IDbConnection, T> fn);
}
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);
        }
    }
}