2013-07-04 26 views
11

Ho un progetto API Web MVC4 ASP.NET con un controller ereditario ApiController che accetta un parametro ODataQueryOptions come uno di i suoi input.Istanziato nuovo System.Web.Http.OData.Query.ODataQueryOptions in nunit test del controller API Web ASP.NET

Sto utilizzando NUnit e Moq per testare il progetto, che mi consente di impostare risposte predefinite dai metodi di repository rilevanti utilizzati da ApiController. Questo funziona, come in:

[TestFixture] 
public class ProjectControllerTests 
{ 
    [Test] 
    public async Task GetById() 
    { 
     var repo = new Mock<IManagementQuery>(); 

     repo.Setup(a => a.GetProjectById(2)).Returns(Task.FromResult<Project>(new Project() 
     { 
       ProjectID = 2, ProjectName = "Test project", ProjectClient = 3 
     })); 

     var controller = new ProjectController(repo.Object); 
     var response = await controller.Get(2); 

     Assert.AreEqual(response.id, 2); 
     Assert.AreEqual(response.name, "Test project"); 
     Assert.AreEqual(response.clientId, 3); 
    } 
} 

La sfida che ho è che, per utilizzare questo modello, ho bisogno di passare nei parametri QueryString relativi al controller così come il repository (questo era in realtà il mio intento). Tuttavia, nel caso di ODataQueryOptions - accettando i metodi ApiController, anche nei casi in cui vorrei utilizzare solo i parametri predefiniti per ODataQueryOptions, ho bisogno di sapere come istanziarne uno. Questo diventa complicato:

  • ODataQueryOptions non implementa un'interfaccia, quindi non posso prendere in giro direttamente.
  • Il costruttore richiede un'implementazione di System.Web.Http.OData.ODataQueryContext, che richiede un'implementazione di qualcosa che implementa Microsoft.Data.Edm.IEdmModel, per cui la documentazione è scarsa e Visual Studio 2012 Trova riferimenti e Visualizza gerarchia chiamate non fornire informazioni (cosa implementa quell'interfaccia?).

Cosa devo fare/C'è un modo migliore per farlo?

Grazie.

risposta

6

Sembra che qualcun altro ha già risposto a questo nei commenti here, ma non è una soluzione completa per il mio caso d'uso (vedi commento qui sotto):

ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); 
modelBuilder.EntitySet<Customer>("Customers"); 
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)), request); 
+2

Bene, dato che il mio EntitySet è derivato da un modello EntityFramework, e sono in gran parte gli oggetti correlati, sembra che ho bisogno di fornire un'EntitySet <> per ogni TEntity nel mio ObjectContext ... è vero? Deve esserci un modo per andare da objectcontext => odataqueryoptions, giusto? – user483679

0

Questa è la soluzione che ho usato nel mio NUnit test per iniettare ODataQueryOptions

private static IEdmModel _model; 
private static IEdmModel Model 
{ 
    get 
    { 
     if (_model == null) 
     { 
      var builder = new ODataConventionModelBuilder(); 

      var baseType = typeof(MyDbContext); 
      var sets = baseType.GetProperties().Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>)); 
      var entitySetMethod = builder.GetType().GetMethod("EntitySet"); 
      foreach (var set in sets) 
      { 
       var genericMethod = entitySetMethod.MakeGenericMethod(set.PropertyType.GetGenericArguments()); 
       genericMethod.Invoke(builder, new object[] { set.Name }); 
      } 

      _model = builder.GetEdmModel(); 
     } 

     return _model; 
    } 
} 

public static ODataQueryOptions<T> QueryOptions<T>(string query = null) 
{ 
    query = query ?? ""; 
    var url = "http://localhost/Test?" + query; 
    var request = new HttpRequestMessage(HttpMethod.Get, url); 
    return new ODataQueryOptions<T>(new ODataQueryContext(Model, typeof(T)), request); 
}