MEF и модульное тестирование с NUnit - PullRequest
4 голосов
/ 17 мая 2010

Несколько недель назад я запрыгнул на платформу MEF (ComponentModel) и теперь использую ее для многих своих плагинов, а также для общих библиотек. В целом, это было здорово, если не считать частых ошибок с моей стороны, которые приводят к срыву отладочных сессий.

Как бы то ни было, мое приложение работало отлично, но изменения кода, связанные с MEF, привели к сбою моих автоматических сборок. Большинство моих модульных тестов проваливались просто потому, что модули, которые я тестировал, зависели от других модулей, которые должны были быть загружены MEF. Я обходил эти ситуации, обходя MEF и непосредственно создавая экземпляры этих объектов.

Другими словами, через MEF у меня будет что-то вроде

[Import]
public ICandyInterface ci { get; set; }

и

[Export(typeof(ICandyInterface))]
public class MyCandy : ICandyInterface
{
    [ImportingConstructor]
    public MyCandy( [Import("name_param")] string name) {}
    ...
}

Но в моих юнит-тестах я бы просто использовал

CandyInterface MyCandy = new CandyInterface( "Godiva");

Кроме того, CandyInterface требует подключения к базе данных, что я обошел, просто добавив тестовую базу данных в мою папку модульных тестов, и я использую NUnit для всех тестов.

Хорошо, вот мои вопросы относительно этой ситуации:

  1. Это плохой способ делать вещи?
  2. Вы бы порекомендовали составлять детали в [SetUp]
  3. Я еще не научился использовать макеты в модульном тестировании - это хороший пример случая, когда я мог бы захотеть смоделировать базовое соединение с базой данных (каким-то образом), чтобы просто вернуть фиктивные данные и на самом деле не требовать базы данных
  4. Если вы уже сталкивались с чем-то подобным, можете ли вы предложить свой опыт и то, как вы решили свою проблему? (или это должно войти в сообщество вики?)

Ответы [ 3 ]

10 голосов
/ 18 мая 2010

Звучит так, как будто вы на правильном пути. Модульный тест должен проверить unit , и это то, что вы делаете, когда создаете экземпляры напрямую. Если вы позволите MEF создавать для вас экземпляры, они будут стремиться к интеграционным тестам . Не то чтобы в интеграционных тестах что-то не так, но модульные тесты, как правило, более удобны в обслуживании, поскольку вы тестируете каждый модуль изолированно.

Вам не нужен контейнер для подключения экземпляров в модульных тестах .

Я вообще рекомендую не создавать фикстуры в SetUp, так как это приводит к анти-паттерну General Fixture .

Рекомендуется заменять зависимости на Test Doubles . Динамические насмешки - это один из самых универсальных способов сделать это, поэтому определенно вы должны изучить их.

0 голосов
/ 19 октября 2012

Я писал о том, как проводить модульные тесты (не nunit, а работает точно так же) с MEF. Хитрость заключалась в том, чтобы использовать MockExportProvider, и я создал тестовую базу для всех моих тестов, чтобы унаследовать их.

Это моя основная функция AutoWire, которая работает для интеграции и модульных тестов:

protected void AutoWire(MockExportProvider mocksProvider, params Assembly[] assemblies){

CompositionContainer container = null;

var assCatalogs = new List<AssemblyCatalog>();

foreach(var a in assemblies)
{
    assCatalogs.Add(new AssemblyCatalog(a));
}

if (mocksProvider != null)
{
    var providers = new List<ExportProvider>();

    providers.Add(mocksProvider); //need to use the mocks provider before the assembly ones            

    foreach (var ac in assCatalogs)
    {
        var assemblyProvider = new CatalogExportProvider(ac);                    
        providers.Add(assemblyProvider);
    }

    container = new CompositionContainer(providers.ToArray());

    foreach (var p in providers) //must set the source provider for CatalogExportProvider back to the container (kinda stupid but apparently no way around this)
    {
        if (p is CatalogExportProvider)
        {
            ((CatalogExportProvider)p).SourceProvider = container;
        }
    }
}
else
{
    container = new CompositionContainer(new AggregateCatalog(assCatalogs));
}

container.ComposeParts(this);        
}

Больше информации на мой пост: https://yoavniran.wordpress.com/2012/10/18/unit-testing-wcf-and-mef/

0 голосов
/ 03 ноября 2010

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

Если вы используете статический контейнер и выполняете импорт через CompositionInitializer.SatisfyImports, вам придется столкнуться с общим анти-шаблоном фикстуры, так как CompositionInitializer.Initialize не может быть вызван более одного раза. Однако вы всегда можете создать CompositionContainer, добавить каталоги и вызвать SatisyImportOnce для самого контейнера. В этом случае вы можете использовать новый CompositionContainer в каждом тесте и избежать столкновения с общим / общим шаблоном защиты

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...