2013-08-03 2 views
2

Для проекта я использую класс CompositeContainer структуры MEF. Теперь я хотел бы сделать модульный тест (с moq), который проверяет, вызван метод ComposeParts (который является методом расширения в AttributedModelServices).Тестирование с помощью Moq, если метод внешней библиотеки называется

Просто издевательство с помощью moq не работает, потому что метод не является виртуальным. Я нашел несколько способов сделать это, но все они заставляют меня менять класс CompositeContainer, чего я не могу сделать.

Есть ли способ в moq, чтобы проверить, вызывается ли не виртуальный метод внешней сторонней библиотеки?

Заранее благодарим за ваш ответ.

пример кода:

public void Load(string path, CompositionContainer container) 
{   
    container.ComposeParts(this);   
} 

Здесь контейнер из MEF библиотеки и ComposeParts метод расширения в System.ComponentModel.Composition имен:

// 
// Summary: 
//  Creates composable parts from an array of attributed objects and composes 
//  them in the specified composition container. 
// 
// Parameters: 
// container: 
//  The composition container to perform composition in. 
// 
// attributedParts: 
//  An array of attributed objects to compose. 
public static void ComposeParts(this CompositionContainer container, params object[] attributedParts); 
+0

Можете ли вы показать пример метода расширения, который вы вызываете? –

+0

Вы пытаетесь проверить, если класс, который не принадлежит вам, вызывает метод? –

+0

Возможно, вы тестируете неправильный фрагмент кода, возможно, вам следует проверить эффекты вызова этого метода в вашем приложении. –

ответ

1

Я не считаю, что можно прямо проверить, был ли вызван метод сторонней библиотеки с помощью Moq, но вы можете проверить побочные эффекты вызова метода. Поскольку вы используете MEF для извлечения реализаций во время выполнения, я бы тестировал, что ваши типы были загружены правильно. Так что если у вас есть что-то вроде этого:

public interface IInterfaceToCompose 
{ 
    string MethodToCreate(); 
} 

[Export(typeof(IInterfaceToCompose))] 
public class ConcreteImplementation1 : IInterfaceToCompose 
{ 
    public string MethodToCreate() 
    { 
     return "Implementation 1"; 
    } 
} 

[Export(typeof(IInterfaceToCompose))] 
public class ConcreteImplementation2 : IInterfaceToCompose 
{ 
    public string MethodToCreate() 
    { 
     return "Implementation 2"; 
    } 
} 

Вы могли бы написать тест, который выглядит примерно так:

[ImportMany(typeof(IInterfaceToCompose))] 
public IInterfaceToCompose ComposedItems { get; set; } 

[Test] 
public void WhenComposingTheComposedItems_ShouldLoadExportedTypes() 
{ 
    Load("testPath", YourContainer); 

    Assert.AreEqual(2, ComposedItems.Count()); 
} 

То, что вы действительно хотите проверить (ИМО) является то, что вы создали свои составленные классы правильно и что все они могут быть загружены MEF CompositionContainer.

Хорошим вторым тестом было бы выполнить начальную загрузку, добавить DLL с третьим разработчиком и убедиться, что конечный счет равен 3 (ваша система динамически загружает новые модули). Это приведет к ошибкам, таким как забывание атрибутов новых реализаций с атрибутом Export, а также убедитесь, что ваши классы правильно подбирают изменения по мере их возникновения.

+0

Я действительно мог бы использовать эту функцию и посмотреть, загружает ли она модули. Но потом я также технически тестирую сторонний код. Мне было интересно, могу ли я это сделать без него. Единственное, что мне нужно знать, это: «он вызывает метод». Если этот метод работает или нет, это еще один модульный тест (и кто-то другой). –

+1

Следующее лучшее, что я могу придумать, было бы сделать интерфейс ICompositionContainer с оболочкой с помощью метода ComposedParts, и вы можете отправить макет для теста и завернутую версию реальной вещи в сценарий тестирования производительности/интеграции. Затем вы можете утверждать, что был вызван метод интерфейса. Хотя это не докажет, что ваш класс-оболочка верен, он докажет, что объект, который принимает интерфейс типа ICompositionContainer, имеет метод ComposeParts (который звучит так, как вам хотелось бы в любом случае). –

+0

Я надеялся, что смогу пропустить установку фиктивного модуля для тестирования метода, но это, по-видимому, единственный способ. Создание обертки и интерфейса просто переводит проблему в оболочку и добавляет ненужный код в тестируемый класс. Поэтому я иду на этот ответ. Спасибо за помощь. –

0

Это метод Load, реализованный в классе ? Вы решили удалить его оттуда? Принимая во внимание принцип единой ответственности, похоже, что ваш класс делает слишком много.

Я бы предложил, чтобы вы разделили функциональность - ваш класс делает любую бизнес-логику, в которой он нуждается. И еще один класс «инфраструктуры», который отвечает за компоновку контейнера - в вашем случае получить экземпляр вашего класса и зарегистрировать его в контейнере.

У вас будет почти такая же проблема, но в другом месте. И это «новое» место будет гораздо более сфокусированным на его функциональности, и вы можете протестировать его изолированно, используя реальный контейнер и изучить его, если будут созданы правильные части.

+0

это именно тот класс, который вы описываете, но так как я хотел дать простой пример, я дал этот код, чтобы все было ясно. –

0

Если вы хотите просто проверить, что метод вызывается, вы можете обернуть CompositionContainer в интерфейсе оболочки, который называется ICompositionContainer, который имеет те же сигнатуры метода. Затем с Moq можно утверждать, что метод был назван:

mock.Verify(cc => cc.ComposeParts(), Times.Once()); 

Отрицательная здесь является то, что вы создаете интерфейс, чтобы скрыть тот факт, что первоначальная реализация не осуществлять для вас.

Пример кода теперь будет:

public void Load(string path, ICompositionContainer container) 
{   
    container.ComposeParts(this);   
} 

Есть примеры других проектов, которые обертывают проблематичным тестовые классы в рамках .NET, такие как SystemWrapper.

Смежные вопросы