我在当前项目中使用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 ,以验证是否正确调用了保存方法。 我使用 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 进行更改。
这可行吗?
答案 0 :(得分:4)
我的分支位于此处:https://github.com/schotime/PetaPoco已经为Database类定义了一个接口。
还有我的新叉https://github.com/schotime/NPoco或nuoco在nuget上具有相同的api。
我会使用其中一种。 ;)
答案 1 :(得分: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公共方法不是虚拟的,我会分叉它,修复代码并向它们发送拉取请求。否则,你的方法对我来说很好。