2015-09-04 6 views
0

У меня есть папка с сборками, каждая из которых содержит реализацию определенного интерфейса (по-разному в каждой сборке). Я написал несколько модульных тестов для этого интерфейса и хотел бы автоматизировать задачу запуска тестов интерфейса для каждой реализации.Автоматическая инъекция зависимостей при тестировании модулей

У меня есть рабочее решение, что мне не нравится:

  • Написать код в реальном классе тест для загрузки (сборки) и создать экземпляр реализаций, хранить их в списке.

  • Напишите каждый тест, чтобы пройти через список реализаций, используя свои утверждения для каждого.

То, что я хочу вместо чтобы запустить все тесты на одном из вариантов осуществления, а затем перейти к следующему, чтобы запустить все тесты снова, и так далее. Моя мысль заключалась в том, чтобы найти способ сделать что-то вроде (программно):

  • Загрузите сборки и создайте экземпляр реализаций - как раньше, но не внутри тестового класса.
  • Создайте экземпляр тестового класса, введя следующую реализацию.
  • Запуск тестов.
  • Перейдите к следующей реализации, повторив процесс.

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

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

+0

Возможно, вам понадобится использовать атрибут 'TestCaseSource' для предоставления типов/экземпляров класса, который вы хотите протестировать. Вам понадобится загрузка сборки и т. Д., Но NUnit затем позаботится о остальной части сантехники для вас. http://www.nunit.org/index.php?p=testCaseSource&r=2.5.9 – forsvarir

+0

'TestCaseSource' - это вариант, я согласен, но не буду добиваться цели: каждый тест для одной реализации, а затем переход к следующая реализация, повторяющая процесс_. Не получив хорошего решения от реализации 'IAddin' и' ISuiteBuilder', я в настоящее время просматриваю 'SuiteAttribute', который выглядит многообещающим. –

ответ

0

Я закончил с использованием NUnit SuiteAttribute.

Этот подход включает в себя создание «зонтика класса», например, так:

namespace Validator { 

    public class AllTests { 

     [Suite] 
     public static IEnumerable Suite { 
      get { 
       var directory = @"[ImplementationAssembliesPath]"; 
       var suite = new ArrayList(); 

       // GetInstances is a method responsible for loading the 
       // assemblys and instantiating the implementations to be tested. 
       foreach (var instance in GetInstances(directory)) { 
        suite.Add(GetResolvedTest(instance)); 
       } 
       return suite; 
      } 
     } 

     // This part is crucial - this is where I get to inject the 
     // implementations to the test. 
     private static Object GetResolvedTest(ICalculator instance) { 
      return new CalculatorTests {Calculator = instance}; 
     } 

     [...] 

} 

Обратите внимание, что тестовый класс имеет свойство для инъекций реализации я хочу. Я выбираю инъекцию свойств, потому что тестировщики обычно не любят других конструкторов. Тем не менее, мне пришлось удалить TestFixtureAttribute из фактического класса тестов (опущен здесь), чтобы не путать Console-Runner с тем, что нужно запустить.

Затем я создал простое консольное приложение, чтобы запустить NUnit Console-Runner с /fixture аргументом:

namespace TestRunner { 

    using System; 
    using NUnit.ConsoleRunner; 

    internal class Program { 

     private static void Main(String[] args) { 
      var testDllPath = @"[TestAssemblyPath]/Validator.dll"; 
      var processArgument = @"/process=Separate"; 
      var domainArgument = @"/domain=Multiple"; 
      var runtimeArgument = @"/framework=4.5"; 
      var shadowArgument = @"/noshadow"; 
      var fixtureArgument = String.Format(@"/fixture={0}", "[Namespace].AllTests"); 

      Runner.Main(new[] { 
       testDllPath, 
       processArgument, 
       domainArgument, 
       runtimeArgument, 
       shadowArgument, 
       fixtureArgument 
      }); 

      Console.ReadLine(); 
     } 

    } 

} 

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

-1

Если вы хотите протестировать фиксированный набор сборок, вам не нужно делать причудливые вещи, например, перемещать сборки или инструктировать тестовые ролики.

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

Базовый класс может выглядеть следующим образом:

public class BaseMyInterfaceImplementationTest 
{ 
    protected MyInterface ClassUnderTest; 

    //Add your tests here with the [Test] attribute: 
    [Test] 
    public void TestScenario1() 
    { 
     //do your test on ClassUnderTest 
    } 
} 

И производные классы, как это:

[TestFixture] 
public class Implementation1Tests : BaseMyInterfaceImplementationTest 
{ 
    [SetUp] 
    public void BaseTestInitialize() 
    { 
     ClassUnderTest = new Implementation1(); 
    } 
} 
+0

Как это помогает при выполнении всех тестов один раз для каждой реализации (из сборок, которые не являются фиксированным набором, а, скорее, нужно загружать во время выполнения)? –

+0

@OskarLindberg, вы правы, мое предлагаемое решение работает только в том случае, если у вас есть фиксированный набор реализаций. –

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