Instantiate new System.Web.Http.OData.Query.ODataQueryOptions in nunit test of ASP.NET Web API controller

风流意气都作罢 提交于 2020-01-01 08:14:34

问题


I have an ASP.NET MVC4 Web API project with an ApiController-inheriting controller that accepts an ODataQueryOptions parameter as one of its inputs.

I am using NUnit and Moq to test the project, which allow me to setup canned responses from the relevant repository methods used by the ApiController. This works, as 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);
    }
}

The challenge I have is that, to use this pattern, I need to pass in the relevant querystring parameters to the controller as well as the repository (this was actually my intent). However, in the case of ODataQueryOptions-accepting ApiController methods, even in the cases where I would like to use just the default parameters for ODataQueryOptions, I need to know how to instantiate one. This gets tricky:

  • ODataQueryOptions does not implement an interface, so I can't mock it directly.
  • The constructor requires an implementation of System.Web.Http.OData.ODataQueryContext, which requires an implementation of something implementing Microsoft.Data.Edm.IEdmModel, for which the documentation is scarce and Visual Studio 2012 Find References and View Call Hierarchy do not provide insight (what implements that interface?).

What do I need to do/Is there a better way of doing this?

Thanks.


回答1:


Looks like someone else already answered this in the comments here, but it's not a complete solution for my use-case (see comment below):

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



回答2:


This is the solution I have been using in my NUnit tests to inject 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);
}


来源:https://stackoverflow.com/questions/17477421/instantiate-new-system-web-http-odata-query-odataqueryoptions-in-nunit-test-of-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!