C# 我在这里怎么用最小起订量?

C# 我在这里怎么用最小起订量?,c#,unit-testing,mocking,moq,asp.net-core-webapi,C#,Unit Testing,Mocking,Moq,Asp.net Core Webapi,我的WEB API项目使用的是一个通用存储库,它实现了如下界面: public interface IGenericEFRepository<TEntity> where TEntity : class { Task<IEnumerable<TEntity>> Get(); Task<TEntity> Get(int id); } public class GenericEFRepository<TEntity> :

我的WEB API项目使用的是一个
通用
存储库,它实现了如下界面:

public interface IGenericEFRepository<TEntity> where TEntity : class
{
    Task<IEnumerable<TEntity>> Get();
    Task<TEntity> Get(int id);
}

public class GenericEFRepository<TEntity> : IGenericEFRepository<TEntity>
    where TEntity : class
{
    private SqlDbContext _db;
    public GenericEFRepository(SqlDbContext db)
    {
        _db = db;
    }

    public async Task<IEnumerable<TEntity>> Get()
    {
        return await Task.FromResult(_db.Set<TEntity>());
    }

    public async Task<TEntity> Get(int id)
    {
        var entity = await Task.FromResult(_db.Set<TEntity>().Find(new object[] { id }));

        if (entity != null && includeRelatedEntities)
        {
            //Some Code
        }
        return entity;
    }
}
public class CustomerControllerTest
{
    CustomerController _controller;
    ICustomerProvider _provider;
    //ICustomerInquiryMockRepository _repo;
    Mock<ICustomerInquiryMockRepository> mockUserRepo;


    public CustomerControllerTest()
    {
        mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
        //_repo = new CustomerInquiryMockRepository();
        _provider = new CustomerProvider(mockUserRepo.Object);
        _controller = new CustomerController(_provider);
    }

    [Fact]
    public async Task Get_WhenCalled_ReturnsOkResult()
    {
        mockUserRepo.Setup(m => m.GetCustomers())
            .Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable()));
        // Act
        var okResult = await _controller.Get();

        // Assert
        Assert.IsType<OkObjectResult>(okResult);
    }


    [Fact]
    public async Task GetById_UnknownCustomerIdPassed_ReturnsNotFoundResult()
    {
        //Arrange
        I don't know how can I use Moq here and in the other parts of my tests

        // Act
        var notFoundResult = await _controller.Get(4);

        // Assert
        Assert.IsType<NotFoundResult>(notFoundResult);
    }

现在我的问题是,当我使用
Mock
模拟
GetCustomers
方法时,
Mock
工作正常,因为我只需将
GetCustomers
方法中的代码粘贴到
CustomerInquiryMockRepository
对象的
Returns
方法中。然而,我真的不知道如何在这个存储库中为我的其他方法使用Mock。我是否应该替换
Return
方法中的任何内容

您可以这样模拟存储库:

var mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
mockUserRepo.Setup(x => x.GetCustomers())
            .Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable());
mockUserRepo.Setup(x => x.GetCustomer(It.IsAny<int>()))
            .Returns(res => Task.FromResult(MockData.Current.Customers.ElementAt(res));
我认为这里的关键是使用
It.is
It.IsAny
基于您想要模拟对象的方式。通常,您还希望模拟生产代码中使用的接口,而不是让生产代码依赖于名称中带有
mock
Test
的内容。我建议不要对名为
icCustomerInquirryMockRepository
的产品代码依赖,如果这确实是您正在做的事情,而不仅仅是您提供的MCVE的一部分

测试通常使用模拟在高级别上测试应用程序的工作流,因此您通常希望模拟您的服务级别,调用控制器,并验证服务是否按预期调用。例如:

// Production class sample
class ProductionController
{
  public ProductionController(IService1 service1, IService2 service2) { }

  public void ControllerMethod()
  {
    var service1Result = service1.Method();
    service2.Method(service1Result);
  }
}

// Test sample
// arrange
var expectedResult = new Service1Result();
var service1 = Mock.Of<IService1>(x => x.Method() == expectedResult);
var service2 = Mock.Of<IService2>(x => x.Method(It.Is<Service1Result>(y => y == expectedResult)));
var controller = new ProductionController(service1, service2);

// act
controller.ControllerMethod();

// assert
Mock.Get(service1).Verify(x => x.Method(), Times.Once);
Mock.Get(service2).Verify(x => x.Method(expectedResult), Times.Once);
//生产类示例
类生产控制器
{
公共产品控制员(IService1服务1,IService2服务2){}
公共无效控制方法()
{
var service1Result=service1.Method();
服务2.方法(服务1结果);
}
}
//试样
//安排
var expectedResult=new Service1Result();
var service1=Mock.Of(x=>x.Method()==expectedResult);
var service2=Mock.Of(x=>x.Method(It.Is(y=>y==expectedResult));
var控制器=新的ProductionController(服务1、服务2);
//表演
controller.ControllerMethod();
//断言
Mock.Get(service1.Verify)(x=>x.Method(),Times.Once);
Mock.Get(service2).Verify(x=>x.Method(expectedResult),Times.one);
正如您从示例中看到的,您并没有检查这两个服务的业务逻辑,您只是验证是否使用预期数据调用了这些方法。测试是围绕被调用方法的验证而建立的,而不是任何特定的分支逻辑


另外,与您的问题无关,Moq还有一个很酷的语法,您可以用于简单的模拟设置:

var repo = Mock.Of<ICustomerInquiryMockRepository>(x => 
    x.GetCustomers() == Task.FromResult(MockData.Current.Customers.AsEnumerable()));
var repo=Mock.Of(x=>
x、 GetCustomers()==Task.FromResult(MockData.Current.Customers.AsEnumerable());

如果需要在存储库上进行其他设置,可以使用
Mock.Get(repo)
。这绝对值得一看,我觉得读起来更好。

只要让模拟存储库返回与未找到对象时真实存储库返回的结果相同的结果即可。这是一个异常,还是一个空结果,或者其他什么取决于存储库是如何实现的。似乎你想得太多了。@mason你能告诉我如何通过证明答案来实现你所说的吗?@mason如果我必须使用实现的真实存储库,那么我必须处理真实数据库,这不是Moq或单元测试的目的。好吗?不,我没说要使用真正的存储库。然而,您需要模拟真正的存储库正在做什么。因此,如果您的真实存储库在传递不在系统中的客户ID时返回
null
,那么您的模拟存储库也应该返回。@mason请提供一个答案,如果可能的话。我需要更多的澄清,谢谢你的回答。如果(includeTransactions&&Customer!=null){Customer.Transactions=MockData.Current.Transactions.Where(b=>b.CustomerId.Equals(CustomerId)).ToList();}
方法的这一部分呢?Mocking更多的是测试交互,而不是测试实际逻辑。您可能希望有一个单元测试,涵盖存储库的具体实现。从
CustomerControllerTest
中,您应该模拟预期输入的预期结果,并将存储库视为“正常工作”的黑盒。(单独)集成测试可以帮助测试整个工作流。竖起大拇指,教我语法模拟。当然,他关于模拟的意图是绝对正确的。这只是为了确保您的程序流和业务交互设置正确&如果有人破坏了预期的流,就破坏构建。如果您需要测试事务性数据,那么随后您可以实施一些集成测试。@E.Moffat您说的是什么,假服务的使用是否正确?我已经用它测试了工作流?我的没有模拟的测试怎么样?如果你说的“假服务”是指
MockData
,那很好。我将更新我的答案,以描述工作流测试通常的外观。
var mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
mockUserRepo.Setup(x => x.GetCustomers())
            .Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable());
mockUserRepo.Setup(x => x.GetCustomer(It.IsAny<int>()))
            .Returns(res => Task.FromResult(MockData.Current.Customers.ElementAt(res));
mockUserRepo.Setup(x => x.GetCustomer(It.Is<int>(y => y == 4)))
            .Returns(res => Task.FromResult(/* error value here */));
// Production class sample
class ProductionController
{
  public ProductionController(IService1 service1, IService2 service2) { }

  public void ControllerMethod()
  {
    var service1Result = service1.Method();
    service2.Method(service1Result);
  }
}

// Test sample
// arrange
var expectedResult = new Service1Result();
var service1 = Mock.Of<IService1>(x => x.Method() == expectedResult);
var service2 = Mock.Of<IService2>(x => x.Method(It.Is<Service1Result>(y => y == expectedResult)));
var controller = new ProductionController(service1, service2);

// act
controller.ControllerMethod();

// assert
Mock.Get(service1).Verify(x => x.Method(), Times.Once);
Mock.Get(service2).Verify(x => x.Method(expectedResult), Times.Once);
var repo = Mock.Of<ICustomerInquiryMockRepository>(x => 
    x.GetCustomers() == Task.FromResult(MockData.Current.Customers.AsEnumerable()));