如何对使用PetaPoco.Database的服务进行单元测试

8
我在当前项目中使用PetaPoco作为微型ORM,我必须说我很喜欢它。然而,我发现自己在一个简单的场景中遇到了困难 - 单元测试使用PetaPoco.Database的服务。
public class MyService : IMyService
{
    private readonly PetaPoco.Database _database;

    public MyService(PetaPoco.Database database)
    {
        _database = database;
    }

    public void SaveSomething(MyObject myObject)
    {
        //...custom logic
        _database.Save(myObject);
    }
}

我正在使用IoC(Castle.Windsor),在需要的地方注入IMyService和PetaPoco.Database。 现在,当我尝试单元测试我的服务时,我无法正确模拟存根PetaPoco.Database,以验证Save方法是否被正确调用。 我使用NUnit和Rhino.Mocks进行单元测试和模拟。
[TestFixture]
public class MyServiceTests
{ 

    private PetaPoco.Database _database;

    [SetUp] 
    public void SetUp()
    {
        _database = MockRepository.GenerateMock<Database>("");
    }

    [Test]
    public void ShouldProperlySaveSomething()
    {
        //Arrange
        var myObject = new MyObject();
        _database.Expect(db => db.Save(Arg<MyObject>.Is.Anything));
        var myService = new MyService(_database);

        //Act
        myService.SaveSomething(myObject);

        //Assert
        _database.VerifyAllExpectations();   
    }

}

我知道如果从PetaPoco.Database中提取一个接口并对其进行模拟,或者通过虚拟化我想要模拟的PetaPoco方法来解决这个问题,但是关键是我不想对PetaPoco进行任何更改。
这可行吗?
2个回答

4

做得好,@Schotime,那正是我需要的!不过我很好奇,你有没有尝试向原始代码库创建拉取请求? - ljubomir
很多时候,但我现在作为库的一部分有更多功能,而且有很多错误修复,所以它们几乎是两个不同的部分。 - Schotime
@chobo2 您需要哪些文档?我已经在这里开始了一些:https://github.com/schotime/NPoco/wiki - Schotime
我没有看到任何额外部分中任何项目的文档。 - chobo2
我不太明白如何使用一对多查询助手。如果您能帮忙解释一下,那就太好了。 - chobo2
显示剩余5条评论

1

您已经使用IMyService抽象了与PetaPoco.Database的交互,那么为什么还需要另一个抽象层呢?使用您当前的方法,您应该能够使用IMyService测试与数据库的交互,例如:

public class AuthenticationService 
{
    private IMyService myService;

    public AuthenticationService(IMyService service) 
    {
        ...
    }

    public void Authenticate(string username, string password)
    {
       var user = myService.GetUser(username); // <-- Hits the database
    }
}

为了测试它,您只需使用IMyService的模拟/存根来模拟交互。

现在关于您的原始解决方案,如果PetaPoco公共方法不是虚拟的,我会分叉它,修复代码并发送拉取请求。否则,您的方法对我来说看起来很好。


1
感谢您的回答,@Hadi。我提出这个问题的原因在于,我想要在隔离环境中测试MyService业务逻辑,即我不想访问数据库,同时我想确保通过PetaPoco触发了数据库调用。在我看来,唯一可能的方法是模拟PetaPoco.Database。 - ljubomir
另一方面,复制代码看起来像是一个不错的解决方案,我可能会尝试一下。 - ljubomir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接