2010-08-18 2 views
6

Возможно ли издеваться над корпоративной библиотекой 5 версии 'Database'? Если так ... как?Mocking Enterprise Lib 5 'Database'

Нет интерфейса IDatabase (что является загадкой, поскольку Microsoft P & P будет больше на шаре о преимуществах тестирования, демонстрирующих такой интерфейс).

У меня есть класс репозитория, который использовал EntLib 5 Application Application Block.

Я выполняю ретро-установку в этом классе и должен изнашивать зависимость от объекта базы данных. Этот класс теперь передал базу данных через свой конструктор и использует объект Database для выполнения операций над Db.

Я использую следующее разрешить экземпляр базы данных, которые будут переданы моей Repository:

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

Я не хочу этих модульных тестов, чтобы стать интеграционные тесты.

Я пробовал использовать Moq для создания динамического макета типа базы данных, но это оказалось непростым, поскольку для базы данных требуется строка подключения и DbProviderFactory в ее конструкторе. Возможно, если была такая вещь, как MockDbProviderFactory.

Это форма, что тестовый модуль принимает:

EntLib UnitTest Attempt to Mock Database

Помимо: Я также найти применение статического регистратора класса очень трудно проверить. Надеюсь, я пропустил здесь какую-то трюк, но я должен сказать, что до сих пор разочарован тестированием.

+0

Извините за мое невежество, но поскольку у вас есть интерфейс для вашего репозитория, не проще было бы издеваться над IFooRepositor вместо базы данных? – thiagoleite

+1

Мне нужно было высмеять экземпляр базы данных EntLib в этом сценарии, чтобы изолировать проверку реализации IFooRepository в отдельности. – holsee

ответ

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 - интерфейс! Подсказка: интерфейсы просты для фальсификации. Почему Microsoft P & Группа P не сделала этого, я не знаю.

+0

Я тоже, хорошо. – holsee

3

FWIW, я смог издеваться над SqlDatabase с помощью Moq. SqlDatabase имеет атрибут SqlClientPermission, который не очень хорошо работает с Castle Windsor (используется Moq). Я должен был явно проинструктировать Castle игнорировать атрибут SqlClientPermission, чтобы заставить тест работать (см. Строку 1 в примере ниже). Ниже приведен пример тестового блока (заимствование примера Стивена Х).

[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."); 
    } 
Смежные вопросы