3

I am migration the our existing API to .net 5 and I face the issue of the unit tests migration. I want to keep tests and test controllers but I could not find a way hot to deal with ODataQueryOptions because this class has been change and I could not find a way to create a ODataQueryOptions any more. All topics which are related to my issue are outdated.

This is the old code how the controller has been tested before the migration

_userController.Request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost/api?$orderby=UserName desc"));
            _queryOptionsUser = new ODataQueryOptions<User>(_queryOptionsUser.Context, _userController.Request);
            PageResult<UserDto> users = _userController.GetUsers(Constants.ValidOrgCode1, _queryOptionsUser);

I would be more than thankful if someone can provide the snipes how to deal with similar issue and be able to test a controller.

2 Answers 2

9

Finally, I ended doing this.

Have the method of the controller to unit test

public PageResult<User> GetAll(ODataQueryOptions<User> odataQuery) 

Unit testing

// Arrange
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<User>("User");
var edmModel = modelBuilder.GetEdmModel();

const string routeName = "odata";
IEdmEntitySet entitySet = edmModel.EntityContainer.FindEntitySet("User");
ODataPath path = new ODataPath(new EntitySetSegment(entitySet));

var request = RequestFactory.Create("GET",
    "http://localhost/api?$top=10&",
    dataOptions => dataOptions.AddModel(routeName, edmModel));

request.ODataFeature().Model = edmModel;
request.ODataFeature().Path = path;
request.ODataFeature().PrefixName = routeName;

var oDataQueryContext = new ODataQueryContext(edmModel, typeof(User), new ODataPath());
var aDataQueryOptions = new ODataQueryOptions<User>(oDataQueryContext, request);

// Act
PageResult<User> users = _userController.GetAll(aDataQueryOptions);

You will need the helper class to generate HttpRequest

public static class RequestFactory
    {
        /// <summary>
        /// Creates the <see cref="HttpRequest"/> with OData configuration.
        /// </summary>
        /// <param name="method">The http method.</param>
        /// <param name="uri">The http request uri.</param>
        /// <param name="setupAction"></param>
        /// <returns>The HttpRequest.</returns>
        public static HttpRequest Create(string method, string uri, Action<ODataOptions> setupAction)
        {
            HttpContext context = new DefaultHttpContext();
            HttpRequest request = context.Request;

            IServiceCollection services = new ServiceCollection();
            services.Configure(setupAction);
            context.RequestServices = services.BuildServiceProvider();

            request.Method = method;
            var requestUri = new Uri(uri);
            request.Scheme = requestUri.Scheme;
            request.Host = requestUri.IsDefaultPort ? new HostString(requestUri.Host) : new HostString(requestUri.Host, requestUri.Port);
            request.QueryString = new QueryString(requestUri.Query);
            request.Path = new PathString(requestUri.AbsolutePath);
            
            return request;
        }

it was taken from here https://github.com/OData/AspNetCoreOData/blob/master/test/Microsoft.AspNetCore.OData.Tests/Extensions/RequestFactory.cs

I hope it will help other who will face the same issue

Sign up to request clarification or add additional context in comments.

2 Comments

I think 'PrefixName' has changed to 'RoutePrefix' and 'dataOptions.AddModel' to 'dataOptions.AddRouteComponents' in the current version
This is working as expected, with above changes suggested by Steve.
1

Galkin's answer works for v8.x. I am stuck on Microsoft.AspNetCore.OData v7.7 and came up with this (critical part for me was having the route builder to call EnableDependencyInjection):

public static HttpRequest CreateHttpRequest(string uri)
{
    IServiceCollection serviceCollection = new ServiceCollection();
    serviceCollection.AddOData();

    IApplicationBuilder appBuilder = new ApplicationBuilder(serviceCollection.BuildServiceProvider());
    IRouteBuilder routeBuilder = new RouteBuilder(appBuilder);
    routeBuilder.EnableDependencyInjection();

    HttpContext context = new DefaultHttpContext();
    context.RequestServices = routeBuilder.ServiceProvider;

    HttpRequest request = context.Request;

    request.Method = "GET";
    var requestUri = new Uri(uri);
    request.Scheme = requestUri.Scheme;
    request.Host = new HostString(requestUri.Host);
    request.QueryString = new QueryString(requestUri.Query);
    request.Path = new PathString(requestUri.AbsolutePath);

    return request;
}

Then create ODataQueryOptions like this:

    requestUri = "http://localhost/odata/foos/?$select=Id,Name";
    var path = new Microsoft.AspNet.OData.Routing.ODataPath();
    var model = CreateEdmModel<FooRow>("foos");
    ODataQueryContext context = new ODataQueryContext(model, typeof(FooRow), path);

    var request = CreateHttpRequest(requestUri);

    var options = new ODataQueryOptions(context, request);

With

    private static IEdmModel CreateEdmModel<TEntity>(string entitySetName) where TEntity : class
    {
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<TEntity>(entitySetName);
        return builder.GetEdmModel();
    }

    public class FooRow
    {
        public Guid Id { get; set; }

        public string Name { get; set; }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.