Я настраиваю интеграционное тестирование для WebAPI с использованием в памяти Owin TestServer, и я получаю сообщение об ошибке были найденыOwin.TestServer неправильно находит несколько контроллеров в Web Api 2
несколько типов, которые соответствуют контроллеру с именем 'значения'. Это может произойти, если маршрут, который обслуживает это запрос («апи/{контроллер}») нашел несколько контроллеров, определенных с же именем, но различные пространства имен, которое не поддерживается
в DefaultHttpControllerTypeResolver.GetControllerTypes() ,
ссылка: small project которая воспроизводит ошибку.
Редактировать
В попытке решить эту проблему, я впоследствии попытался использовать обычный HttpServer, HttpSelfHostServer и Owin.SelfHost в дополнение к Owin.TestServer, но все они сталкиваются с той же проблемой.
Редактировать Edit
Узор, при выполнении тестов в пакете, первый тест проходит, но последующие тесты завершаются с ошибкой «Несколько типов были найдены» ошибка. Это происходит в моем фактическом проекте, а также в том, что предоставляется простой репрограммный проект, который дает точно такое же поведение. Однако, как вы можете видеть в репродуцированном проекте, существует только один ValuesController, несмотря на то, что сообщение об ошибке требует иного, и в моем фактическом проекте также не существует нескольких типов контроллеров.
Что я имею в своем основном проекте - это базовый класс интеграционных тестов, который может быть запущен на реальном сервере IIS, а также в памяти с использованием Owin TestServer с использованием производных классов. Когда я запускаю тесты против IIS, они все проходят; когда я запускаю тесты по-разному с помощью Owin TestServer, все они проходят; но когда я запускаю их как пакет в памяти, первый проходит, но остальное всегда терпит неудачу с вышеупомянутой ошибкой.
В попытке получить свежий TestServer перед каждым тестом я создаю новый в TestInitialize(), но это не устраняет проблему.
Учитывая, что все тесты проходят при работе с IIS, я предполагаю, что они должны проходить при запуске с Owin Test Server.
Вот краткое изложение соответствующего кода: WebAPI очень slighly модифицирована из коробки проекта, созданного в Visual Studio 2015.
Здесь класс запуска используется для создания Owin.TestServer
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
var tracing = config.EnableSystemDiagnosticsTracing();
tracing.IsVerbose = true;
tracing.MinimumLevel = System.Web.Http.Tracing.TraceLevel.Debug;
// The assembly resolver is shown below.
config.Services.Replace(typeof(IAssembliesResolver), new TestApiAssemblyResolver());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
app.UseWebApi(config);
}
}
Тест инициализации выглядит следующим образом ...
[TestInitialize()]
public void MyTestInitialize()
{
server = TestServer.Create<Startup>();
this.HttpClient = server.HttpClient;
}
Вот сборка распознаватель используется для загрузки сборки WebAPI в тест. Без этого тесты терпят неудачу с ошибкой Http NotFound.
public class TestApiAssemblyResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
List<Assembly> baseAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "webapiCheck.dll");
/*
You can try unreferencing webapiCheck.dll from this project but it makes no difference.
*/
//var path = @"Your path...Documents\visual studio 2015\Projects\WebApiCheck\WebApiCheck\bin\webapiCheck.dll";
var controllersAssembly = Assembly.LoadFrom(path);
baseAssemblies.Add(controllersAssembly);
return baseAssemblies;
}
}
Вот тестовый метод ...
[TestMethod]
public async Task GetValues()
{
uri = "api/values";
var response = await GetAsync();
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<IEnumerable<string>>();
Assert.AreEqual(2, result.Count());
}
else
{
Assert.Fail(response.ReasonPhrase);
}
}
Я попытался заменить DefaultHttpControllerSelector работать вокруг проблемы, но встречаются ошибки там, потому что base.GetControllerMapping() иногда не возвращает результат.
public class BypassCacheSelector : DefaultHttpControllerSelector
{
private readonly HttpConfiguration _configuration;
public BypassCacheSelector(HttpConfiguration configuration)
: base(configuration)
{
_configuration = configuration;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var path = ConfigurationManager.AppSettings["ApiAssemblyLocation"];
var assembly = Assembly.LoadFrom(path);
var types = assembly.GetTypes(); //GetExportedTypes doesn't work with dynamic assemblies
var matchedTypes = types.Where(i => typeof(IHttpController).IsAssignableFrom(i)).ToList();
// base.GetControllerMapping() sometimes returns no result;
var map = base.GetControllerMapping();
string absPath = request.RequestUri.AbsolutePath;
var candidateName = absPath.Substring(absPath.LastIndexOf("/")+1);
string controllerName = null;
foreach (var m in map)
{
if (candidateName.StartsWith(m.Key))
{
controllerName = m.Key;
break;
}
}
var matchedController =
matchedTypes.FirstOrDefault(i => i.Name.ToLower() == controllerName.ToLower() + "controller");
return new HttpControllerDescriptor(_configuration, controllerName, matchedController);
}
}
Чтобы убедиться, что проблема не связана с атрибутом маршрутизации я удалил атрибут маршрутизации от REPRO проекта и действительно проблема сохраняется: при запуске поодиночке тесты проходят, но при запуске в партии они не с той же ошибкой ,
Если кто-то может указать, как правильно использовать Owin.TestServer с WebApi, я был бы признателен.