Dapper:单元测试SQL查询

时间:2013-12-09 01:24:20

标签: c# .net unit-testing tdd dapper

我开始使用微型ORM Dapper,我使用Dapper Rainbow。我想测试查询和他们检索的数据。

我的意思是,例如,我有 UserService 和方法 GetAll(),我想测试sql查询是从一些用户检索所有用户列表(不是来自数据库,因为我希望测试快速)。你知道我怎么能这样做吗?

我的服务类(以及我想测试的方法):

public static class UserService{
    public static IEnumerable<User> GetAll(){
        return DB.Users.All();
    }
}

您对单元测试查询和数据检索有什么建议吗?

由于

2 个答案:

答案 0 :(得分:8)

我建议阅读依赖注入和存储库模式。如果你采用上面代码中的方法,你将很难模拟出依赖关系,因为类和方法是静态的。

这是一种更好的方法。

public interface IUserRepository
{
   IEnumerable<User> GetAll()
}

public class UserRepository : IUserRepository
{
  public IEnumerable<User> GetAll()
  { 
    return DB.Users.All();
  }
}

public class UserService
{
    IUserRepository _userRepository;
    public UserService(IUserRepository userRepository)
    {
      _userRepository = userRepository
    }

    public Enumerable<User> GetAll(){
        return _userRepository.GetAll();
    }
}

现在进行测试,您可以模拟您的存储库。我使用一个名为NSubstitute的模拟框架,在我看来它比上面提到的其他框架简单得多,但这是个人偏好。首先,您可以在没有任何模拟框架的情况下编写测试。

public class FakeUserRepository : IUserRepository
{
  public IEnumerable<User> GetAll()
  { 
    return new List<User> { new User {FirstName='Bob', LastName='Smith'}, };
  }
}

在你的考试中

[Test]
public void GetAll_ShouldReturnAllFromFake()
{
   // Arrrange
   var userService = new UserService(new FakeUserRepository())
   // Act
   var result = userService.GetAll();
   // Assert
   var user = result[0];
   Assert.AreEqual("Bob", user.FirstName);
   Assert.AreEqual("Smith", user.LastName);   
}

这个例子有点人为,因为测试你可以从假存储库中获取数据并没有多大意义。你如何在现实中使用它是因为你的服务中有一些业务逻辑说回到用户然后检查它们是否比某个年龄或某些年龄大。例如UserService上的IsLegalDrivingAge方法。

答案 1 :(得分:2)

使用Dapper,您的SQL可能是字符串文字,可能与C#条件混合,语法未验证,DB引用可能错误。你的测试直觉很好。但是,针对真实数据库运行代码是判断它是否输出有效查询的唯一方法。所以你需要的测试是集成测试。这并不难,您可以使用单元测试框架来完成它,但由于测试必须访问真正的数据库,您可能不希望在运行单元测试的任何地方运行它,而不是在构建服务器上运行它。

然后,由于Dapper是ADO的扩展方法,要对使用查询的代码进行单元测试,您需要将其包装在存储库模式中。 Dapper Wrapper似乎是这里的工具。

如果所有这些看起来都不必要,请尝试QueryFirst(免责声明:我写了)。您在一个真实的SQL窗口中编写SQL,连接到您的数据库,在您键入时验证了sql。每次保存文件时,您的查询都会针对您的数据库进行集成测试,而无需您抬起手指。然后,如果查询运行,QueryFirst会生成包装器代码以允许您使用它,包括一个接口,这样您就可以在单元测试使用代码时轻松模拟真实查询。那必须向前迈出一步,不是吗?