2013-06-05 4 views
3

Я пытаюсь выполнить модульное тестирование EntitySetController. Я могу проверить Get, но у вас проблемы с тестированием метода Post.Как я могу протестировать EntitySetController

Я играл с SetODataPath и SetODataRouteName, но когда я вызываю this.sut.Post (сущность), я получаю много ошибок относительно отсутствующего заголовка местоположения, отсутствующего пути OData-Path, отсутствующих маршрутов.

Я нахожусь в конце своего ума. Есть ли кто-нибудь, кто успешно тестирует свой EntitySetController?

Есть ли у меня идеи? Возможно, мне нужно проверить только защищенные переопределенные методы из моей реализации EntitySetController? Но как я могу проверить защищенные методы?

Благодарим за помощь

ответ

5

Пришел сюда для поиска решения. Это, похоже, работает, но не уверен, что есть лучший способ.

Контроллер необходим минимум CreateEntity и GetKey переопределениях:

public class MyController : EntitySetController<MyEntity, int> 
{ 
    protected override MyEntity CreateEntity(MyEntity entity) 
    { 
     return entity; 
    } 

    protected override int GetKey(MyEntity entity) 
    { 
     return entity.Id; 
    } 
} 

Где MyEntity очень просто:

public class MyEntity 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

Похоже, вам нужно как минимум: + запрос с URI + 3 ключа в заголовке запроса, MS_HttpConfiguration, MS_ODataPath и MS_ODataRouteName + Конфигурация HTTP с маршрутом

[TestMethod] 
    public void CanPostToODataController() 
    { 
     var controller = new MyController(); 

     var config = new HttpConfiguration(); 
     var request = new HttpRequestMessage(); 

     config.Routes.Add("mynameisbob", new MockRoute()); 

     request.RequestUri = new Uri("http://www.thisisannoying.com/MyEntity"); 
     request.Properties.Add("MS_HttpConfiguration", config); 
     request.Properties.Add("MS_ODataPath", new ODataPath(new EntitySetPathSegment("MyEntity"))); 
     request.Properties.Add("MS_ODataRouteName", "mynameisbob"); 

     controller.Request = request; 

     var response = controller.Post(new MyEntity()); 

     Assert.IsNotNull(response); 
     Assert.IsTrue(response.IsSuccessStatusCode); 
     Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); 
    } 

Я не слишком уверен в IHttpRoute, в исходном коде САШ (я должен был связать с этим, чтобы понять это все из) тесты используют издевается этого интерфейса. Поэтому для этого теста я просто создаю макет этого и реализую свойство RouteTemplate и метод GetVirtualPath. Все остальные на интерфейсе не использовались во время теста.

public class MockRoute : IHttpRoute 
{ 
    public string RouteTemplate 
    { 
     get { return ""; } 
    } 

    public IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values) 
    { 
     return new HttpVirtualPathData(this, "www.thisisannoying.com"); 
    } 

    // implement the other methods but they are not needed for the test above  
} 

Это работает для меня, однако я действительно не слишком уверен в ODataPath и IHttpRoute и как правильно его установить.

+0

Спасибо за ваш ответ. Это выглядит хорошо для меня. В то же время я тестирую свой OData-контроллер с вызовом защищенных методов и доверяю правильной реализации из команды Web.API и в своих тестах интеграции. –

1

В дополнение к ответу от @mynameisbob, я обнаружил, вы, возможно, потребуется установить HttpRequestContext, а также о свойствах запроса:

var requestContext = new HttpRequestContext(); 
requestContext.Configuration = config; 
request.Properties.Add(HttpPropertyKeys.RequestContextKey, requestContext); 

мне нужны вышеуказанные дополнения, например, при создании HttpResponseMessage в следующим образом:

public virtual HttpResponseException NotFound(HttpRequestMessage request) 
    { 
     return new HttpResponseException(
      request.CreateResponse(
       HttpStatusCode.NotFound, 
       new ODataError 
       { 
        Message = "The entity was not found.", 
        MessageLanguage = "en-US", 
        ErrorCode = "Entity Not Found." 
       } 
      ) 
     ); 
    } 

Не имея набор HttpRequestContext, описанный выше метод будет сгенерировано аргумент Null исключение как метод расширения CreateResponse пытается получить HttpConfiguration от HttpRequestContext (а не непосредственно из HttpRequest).

0

Кроме того, чтобы получить правильные значения заголовка местоположения и т. Д., Вы действительно хотите вызвать код конфигурации приложения OData для вашего веб-приложения Api.

Таким образом, вместо того, чтобы использовать:

config.Routes.Add("mynameisbob", new MockRoute()); 

Вы должны отделить часть класса WebApiConfig, который устанавливает свои OData маршруты в отдельный класс (например, ODataConfig) и использовать, чтобы зарегистрировать правильные маршруты для испытаний :

например,

ODataConfig.Register(config); 

Единственные вещи, которые вы затем должны следить за то, что следующие строки соответствуют конфигурации маршрутизации:

request.Properties.Add("MS_ODataPath", new ODataPath(new EntitySetPathSegment("MyEntity"))); 
request.Properties.Add("MS_ODataRouteName", "mynameisbob"); 

Итак, если ваш веб-конфигурации API OData выглядит следующим образом:

config.Routes.MapODataRoute("ODataRoute", "odata", GetEdmModel()); 

    private static IEdmModel GetEdmModel() 
     { 
      ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); 
      modelBuilder.EntitySet<MyEntity>("MyEntities"); 
      IEdmModel model = modelBuilder.GetEdmModel(); 
      return model; 
     } 

Тогда это правильная конфигурация:

request.Properties.Add("MS_ODataPath", new ODataPath(new EntitySetPathSegment("MyEntities"))); 
request.Properties.Add("MS_ODataRouteName", "ODataRoute"); 

С этим на месте заголовок вашего местоположения будет сгенерирован правильно.

1

OK обновленный ответ.

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

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

// Register OData configuration with HTTP Configuration object 
// Create an ODataConfig or similar class in App_Start 
ODataConfig.Register(config); 

// Get OData Parameters - suggest exposing a public GetEdmModel in ODataConfig 
IEdmModel model = ODataConfig.GetEdmModel(); 
IEdmEntitySet edmEntitySet = model.EntityContainers().Single().FindEntitySet("Orders"); 
ODataPath path = new ODataPath(new EntitySetPathSegment(edmEntitySet)); 

// OData Routing Convention Configuration 
var routingConventions = ODataRoutingConventions.CreateDefault(); 

// Attach HTTP configuration to HttpRequestContext 
requestContext.Configuration = config; 

// Attach Request URI 
request.RequestUri = requestUri; 

// Attach Request Properties 
request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, config); 
request.Properties.Add(HttpPropertyKeys.RequestContextKey, requestContext); 
request.Properties.Add("MS_ODataPath", path); 
request.Properties.Add("MS_ODataRouteName", "ODataRoute"); 
request.Properties.Add("MS_EdmModel", model); 
request.Properties.Add("MS_ODataRoutingConventions", routingConventions); 
request.Properties.Add("MS_ODataPathHandler", new DefaultODataPathHandler()); 
0

В дополнение ко всему здесь, мне пришлось вручную прикрепить контекст запрос, а также создать данные маршрута. К сожалению, я не нашел для модульного тестирования без зависимости от конфигурации маршрута/модели.

Таким образом, используя маршрут под названием «ODataRoute», которая является частью нормальной конфигурации, установленной в моем статическом ODataConfig.Configure() методе (такой же, как и выше, он создает модель и вызывает кучу MapODataServiceRoute), следующий код работает, чтобы подготовить контроллер для теста:

protected static void SetupControllerForTests(ODataController controller, 
    string entitySetName, HttpMethod httpMethod) 
{ 
    //perform "normal" server configuration 
    var config = new HttpConfiguration(); 
    ODataConfig.Configure(config); 

    //set up the request 
    var request = new HttpRequestMessage(httpMethod, 
     new Uri(string.Format("http://localhost/odata/{0}", entitySetName))); 

    //attach it to the controller 
    //note that this will also automagically attach a context to the request! 
    controller.Request = request; 

    //get the "ODataRoute" route from the configuration 
    var route = (ODataRoute)config.Routes["ODataRoute"]; 

    //extract the model from the route and create a path 
    var model = route.PathRouteConstraint.EdmModel; 
    var edmEntitySet = model.FindDeclaredEntitySet(entitySetName); 
    var path = new ODataPath(new EntitySetPathSegment(edmEntitySet)); 

    //get a couple more important bits to set in the request 
    var routingConventions = route.PathRouteConstraint.RoutingConventions; 
    var pathHandler = route.Handler; 

    //set the properties of the request 
    request.SetConfiguration(config); 
    request.Properties.Add("MS_ODataPath", path); 
    request.Properties.Add("MS_ODataRouteName", "ODataRoute"); 
    request.Properties.Add("MS_EdmModel", model); 
    request.Properties.Add("MS_ODataRoutingConventions", routingConventions); 
    request.Properties.Add("MS_ODataPathHandler", pathHandler); 

    //set the configuration in the request context 
    var requestContext = (HttpRequestContext)request.Properties[HttpPropertyKeys.RequestContextKey]; 
    requestContext.Configuration = config; 

    //get default route data based on the generated URL and add it to the request 
    var routeData = route.GetRouteData("/", request); 
    request.SetRouteData(routeData); 
} 

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

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