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) 在需要的地方注入IMyServicePetaPoco.Database

现在,当我尝试对我的服务进行单元测试时,我无法正确模拟存根PetaPoco.Database以验证Save方法是否被正确调用。我正在使用NUnitRhino.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进行更改一点也不。

这是可行的吗?

4

2 回答 2

4

我的分支位于此处:https ://github.com/schotime/PetaPoco已经为 Database 类定义了一个接口。

还有我的新 Fork https://github.com/schotime/NPoco或 NPoco on nuget 具有相同的 api。

我会使用其中之一。;)

于 2012-05-28T08:36:00.017 回答
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 公共方法不是虚拟的,我会分叉它,修复代码并向他们发送拉取请求。否则,您的方法对我来说看起来不错。

于 2012-05-28T03:23:26.073 回答