Модуль Autofac модульного тестирования веб-API ASP.NET с BuildManager.GetReferencedAssemblies () - PullRequest
0 голосов
/ 08 марта 2019

Работа над проектом в ASP.NET Web API 2, в котором в качестве контейнера IoC используется Autofac. Этот проект размещен на IIS, и в моем модуле Autofac я использую следующий метод для сканирования сборок:

var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();

Почему?

https://docs.autofac.org/en/latest/register/scanning.html#iis-hosted-web-applications

Но сейчас мы проводим модульные тесты, используя NUnit, во время моей настройки я регистрирую свой модуль, который использует этот метод. Теперь я получаю следующее исключение при выполнении моих тестов:

System.InvalidOperationException: 'This method cannot be called during the application's pre-start initialization phase.'

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

Способ установки NUnit:

[TestFixture]
public abstract class ApplicationTestBase
{
    [SetUp]
    public override void Init()
    {
        var builder = new ContainerBuilder();

        // If the class requires auto mapper mapping, initialize them
        // We do this in order not to init them for every test => optimalisation!
        if (GetType().GetCustomAttributes<RequiresAutoMapperMappingsAttribute>(false) != null)
        {
            builder.RegisterModule<AutoMapperModule>();
        }

        this.Container = builder.Build();
    }
}

Нужно ли создавать новый модуль специально для моих юнит-тестов или есть другой способ для этого?

AutoMapperTest

[RequiresAutoMapperMappings]
[TestFixture]
public class AutoMapperTests : ApplicationTestBase
{
    [Test]
    public void Assert_Valid_Mappings()
    {
        Mapper.AssertConfigurationIsValid();
    }
}

UPDATE

Как говорил Кирилл: зачем вам Ioc в ваших юнит-тестах? Я отправился на поиски, и вам действительно не нужно использовать Ioc в своих тестах. Итак, я отказался от Ioc и инициализировал конфигурацию маппера, выполнив:

        Mapper.Initialize(configuration => 
        {
            var asm = AppDomain.CurrentDomain.GetAssemblies()
                        .Where(a => a.FullName.StartsWith("ProjectWebService."));

            configuration.AddProfiles(asm);
        });

1 Ответ

0 голосов
/ 11 марта 2019

Я бы рекомендовал отделить логику «как загрузить сборки» от «логики сканирования сборок и зарегистрировать модули».

Прямо сейчас я предполагаю, что у вас есть что-то подобное в одном методе.

public IContainer BuildContainer()
{
  var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
  var builder = new ContainerBuilder();
  builder.RegisterAssemblyTypes(asm);
  var container = builder.Build();
}

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

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

public IContainer BuildContainer(Func<IEnumerable<Assembly>> assemblyLoader = null)
{
  IEnumerable<Assembly> asm = null;
  if (assemblyLoader != null)
  {
    asm = assemblyLoader();
  }
  else
  {
    asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
  }

  var builder = new ContainerBuilder();
  builder.RegisterAssemblyTypes(asm);
  var container = builder.Build();
}

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

var container = BuildContainer(() => AppDomain.GetAssemblies());

Есть много способов сделать это подкачкой. Это может быть что угодно, от статического свойства, которое вы можете установить где-то, до виртуального метода, который вы можете где-то переопределить. Дело в том, что, разделив логику загрузки сборок, вы можете заставить работать поведение во время тестирования, но все равно использовать поведение регистрации, к которому вы стремитесь.

...