2010-08-18 103 views
6

是否可以嘲笑企业库5版本的'数据库'?如果是这样......怎么样?嘲笑企业库5'数据库'

有没有IDatabase接口(这是一个谜,因为我虽然微软P将更多地暴露这种接口暴露测试性的好处)。

我有一个使用EntLib 5数据访问应用程序块的Repository类。

我是复古适合单元测试到这个类,并需要嘲笑依赖于数据库对象。这个类是现在通过其构造函数传递数据库,并使用数据库对象在Db上执行操作。

我使用以下方法来解决数据库的实例来传递给我的信息库:

Container.RegisterType<IFooRepository, FooRepository>(
    new InjectionConstructor(
     EnterpriseLibraryContainer.Current.GetInstance<Database>("FooDbConnStr") 
    ) 
); 

我不希望将这些单元测试成为集成测试。

我已经尝试过使用Moq创建数据库类型的动态模拟,但事实证明这很棘手,因为数据库在其构造函数中需要连接字符串和DbProviderFactory。也许,如果有这样的事情,一个MockDbProviderFactory

这是单元测试正在采取以下形式:

EntLib UnitTest Attempt to Mock Database

题外话:我也发现使用一个静态的Logger类很难测试的。希望我在这里错过了一些技巧,但是我必须说我对迄今为止的可测试性感到失望。

+0

对不起我的无知,但你有一个接口为您的存储库,岂不是更容易嘲笑IFooRepository而不是数据库? – thiagoleite 2012-07-13 17:24:48

+1

我需要在此场景中模拟EntLib数据库实例,以便单独测试IFooRepository的实现。 – holsee 2012-07-17 22:06:07

回答

2

我用FakeItEasy http://code.google.com/p/fakeiteasy/

我创建了一个SqlDatabase模型(从具有友好构造函数的数据库中继承)将它传递给FooRepostory,称为测试函数,并声明了对数据库进行的预期调用。

[Test] 
public void FooRepo_CallsCorrectSPOnDatabase() 
{ 
    var mockDb = A.Fake<SqlDatabase>(x => x.WithArgumentsForConstructor(new object[] { "fakeconnStr" })); 
    var sut = new FooRepository(mockDb); 
    sut.LoadFoosById(1); 
    A.CallTo(() => mockDb.GetStoredProcCommand(Db.SProcs.GetFoosById)).MustHaveHappened(Repeated.Once); 
} 
1

数据库是一个抽象基类,而DbProviderFactory也是抽象的,所以你可以把它们都模拟出来。只要你嘲笑你在数据库类型上调用的操作(几乎所有的东西都是虚拟的,所以你应该在那里确定),你实际上并不需要在提供者工厂中做任何事情。连接字符串可以只是空或空或任何其他。

1

我个人装载了源代码并使用ReSharper为数据库对象提取接口。它重建,我用我的自定义二进制文件。 Wala - 一个界面!提示:接口很容易模拟。为什么微软P组没有这样做,我不知道。

+0

我也不是,好主意。 – holsee 2010-12-26 22:09:09

3

FWIW,我能够使用Moq模拟一个SqlDatabase。 SqlDatabase具有SqlClientPermission属性,它与Castle Windsor(Moq使用)不兼容。我必须明确指示Castle忽略SqlClientPermission属性才能使测试正常工作(请参见下面示例中的第1行)。以下是一个样本单元测试(借用Steven H的例子)。

[TestMethod] 
    public void FooRepo_CallsCorrectSPOnDatabase() 
    { 
     Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add(typeof(System.Data.SqlClient.SqlClientPermissionAttribute)); 
     var mockSqlDb = new Mock<SqlDatabase>("fake connection string"); 
     mockSqlDb.Setup(s => s.GetStoredProcCommand("sp_GetFoosById")); 
     var sut = new FooRepository(mockSqlDb); 
     sut.LoadFoosById(1); 
     mockSqlDb.Verify(s => s.GetStoredProcCommand("sp_GetFoosById"), Times.Once(), "Stored Procedure sp_GetFoosById was not invoked."); 
    }