使用 .net 对 OData Web API 进行单元测试

问题描述 投票:0回答:2

我正在尝试在 .Net OData Web API 上实现单元测试用例。然而,我面临的问题是,我在 Http 请求 URL 中传递过滤器来过滤数据,但收到了与我发送的相同类型的模拟数据。需要助手我错了什么以及哪里错了。

下面是我的代码

这是客户控制器

public class CustomersController : ODataController
    {
        private readonly ICustomerRepository _repository;
        public CustomersController()
        {
            _repository = new CustomerRepository(new ODataSampleEntities());
        }

        public CustomersController(ICustomerRepository repository)
        {
            // this.genericRepository = repository;//new Repository<Customer>();
            _repository = repository;
        }
    
        [EnableQuery]
        public IQueryable<Customer> Get()
        {
            return _repository.GetAllCustomers();
        }
       
    }

客户模型

public partial class Customer
{
        public int Id { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
        public string Address { get; set; }
}

存储库

    public interface ICustomerRepository
    {
        //IEnumerable<Customer> GetAllCustomers();
        IQueryable<Customer> GetAllCustomers();
    }

public class CustomerRepository: ICustomerRepository
    {
        private readonly ODataSampleEntities _context;

        public CustomerRepository(ODataSampleEntities context)
        {
            _context = context;
        }

        public virtual IQueryable<Customer> GetAllCustomers()
        {
            return _context.Customers;
        }
    }

下面是单元测试用例代码

public class CustomerControllerTests
    {
        [TestMethod]
        public void GetAllCustomers_ShouldReturnAllCustomers()
        {
            // Arrange
            var customers = new List<Customer>
            {
                new Customer { Id = 1, Name = "John", Country = "USA", Address = "USA" },
                new Customer { Id = 2, Name = "Sandesh", Country = "India", Address = "Goa India" }
            };
            var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:44395/Customers?$filter=Name eq 'Sandesh' & $top=1");

            HttpRouteCollection routes = new HttpRouteCollection();
            HttpConfiguration config = new HttpConfiguration(routes) { IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always };
            var Customerbuilder = new ODataConventionModelBuilder();
            Customerbuilder.EntitySet<Customer>("Customer");
            var model = Customerbuilder.GetEdmModel();



            // attempting to register at least some non-OData HTTP route doesn't seem to help
            routes.MapHttpRoute("Default", "{controller}/{action}");
            config.MapODataServiceRoute("odata", "odata", model);
            config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
            config.EnableDependencyInjection();
            config.EnsureInitialized();

            request.SetConfiguration(config);
            ODataQueryContext context = new ODataQueryContext(
                model,
                typeof(Customer),
                new ODataPath(
                    new Microsoft.OData.UriParser.EntitySetSegment(
                        model.EntityContainer.FindEntitySet("Customer"))
                )
            );

            var mockRepository = new Mock<ICustomerRepository>();
            mockRepository.Setup(r => r.GetAllCustomers()).Returns(customers.AsQueryable());
            mockRepository.SetReturnsDefault<IEnumerable<Customer>>(customers.AsQueryable());

            // Create the controller
            var controller = new CustomersController(mockRepository.Object);
            controller.Request = request;

            var options = new ODataQueryOptions<Customer>(context, request);
            //var response = controller.Get(); //as ViewResult;

            // Act
            var result = controller.Get();

            // Assert
            Assert.IsNotNull(result);

             Assert.IsInstanceOfType(result, typeof(IEnumerable<Customer>));

            var contentResult = result;
            Assert.IsNotNull(contentResult);
            Assert.AreEqual(1, contentResult.Count());
            Assert.AreEqual("Sandesh", contentResult.First().Name);
        }
    }

每次运行单元测试时,即使我通过请求 Url 传递过滤器查询,它也会给我相同的模拟数据。请协助我在 OData Web API 控制器上实现并执行单元测试用例,该控制器将过滤数据并返回响应。

c# entity-framework unit-testing asp.net-web-api odata
2个回答
0
投票

在单元测试代码中,您将模拟存储库设置为始终返回同一组客户,无论请求 URL 中应用的过滤器如何。这就是为什么每次运行单元测试时都会获得相同的模拟数据。

要在单元测试中模拟过滤行为,您需要修改模拟存储库设置以考虑请求 URL 中提供的过滤器参数并相应地返回过滤后的数据。

以下是实现这一目标的方法:

修改您的单元测试方法以在请求 URL 中包含过滤器参数:

[TestMethod]
public void GetAllCustomers_ShouldReturnFilteredCustomers()
{
    // ... (existing code)

    // Modify the request URL to include the filter parameter
    var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:44395/Customers?$filter=Name eq 'Sandesh'&$top=1");

    // ... (existing code)
}

更新模拟存储库的设置以返回过滤后的数据:

[TestMethod]
public void GetAllCustomers_ShouldReturnFilteredCustomers()
{
    // ... (existing code)

    var customers = new List<Customer>
    {
        new Customer { Id = 1, Name = "John", Country = "USA", Address = "USA" },
        new Customer { Id = 2, Name = "Sandesh", Country = "India", Address = "Goa India" }
    };

    // Modify the mock repository setup to consider the filter parameter
    mockRepository.Setup(r => r.GetAllCustomers())
                  .Returns((string filter) => 
                  {
                      // Implement filtering based on the filter parameter
                      if (string.IsNullOrEmpty(filter))
                      {
                          return customers.AsQueryable(); // Return all customers if no filter
                      }
                      else
                      {
                          // Parse the filter and apply it to the customer list
                          var odataQuery = new ODataQueryOptions<Customer>(
                              new ODataQueryContext(model, typeof(Customer)), 
                              request
                          );
                          var filteredCustomers = odataQuery.ApplyTo(customers.AsQueryable());
                          return filteredCustomers as IQueryable<Customer>;
                      }
                  });

    // ... (existing code)
}

通过此设置,模拟存储库现在会将请求 URL 中指定的过滤器应用于客户列表,并在您调用

controller.Get()
时相应地返回过滤后的数据。这应该使您能够正确测试 OData Web API 控制器的过滤行为。


0
投票

我稍微修改了@Saeed Gholamzadeh 建议的答案,它起作用了。

[TestMethod]
public void GetAllCustomers_ShouldReturnFilteredCustomers()
{
    // ... (existing code)

    var customers = new List<Customer>
    {
        new Customer { Id = 1, Name = "John", Country = "USA", Address = "USA" },
        new Customer { Id = 2, Name = "Sandesh", Country = "India", Address = "Goa India" }
    };

    // Modify the mock repository setup to consider the filter parameter
    mockRepository.Setup(r => r.GetAllCustomers())
                  .Returns(() => 
                  {
                          // Parse the filter and apply it to the customer list
                          var odataQuery = new ODataQueryOptions<Customer>(
                              new ODataQueryContext(model, typeof(Customer)), 
                              request
                          );
                          var filteredCustomers = odataQuery.ApplyTo(customers.AsQueryable());
                          return filteredCustomers as IQueryable<Customer>;
                  });

    // ... (existing code)
}

这里我删除了一个条件来检查是否应用了过滤器。

© www.soinside.com 2019 - 2024. All rights reserved.