控制器 API 使用 xUnit/Moq 进行测试 - 控制器为空

Controller API Testing with xUnit/Moq - Controller is null

我是单元测试的新手,所以我的问题可能出在我的代码上,而不是 Moq 框架上,但问题是。

我将 .Net Core 与 xUnit 和 Moq 框架一起使用,我或多或少地遵循了他们 documentation 的说明。我正在尝试测试路由 api/user 以获取所有用户,问题在于断言响应是包含 <IEnumerable<User>>ObjectResult。无论我尝试什么,result.Value 始终为空。第一个断言顺利通过。

我建立了一个控制台项目来调试它,发现了一些有趣的东西。 Visual Studio 中测试方法中控制器的值为空。在 VS Code 中,调试器中的值显示 Unknown Error: 0x00000....

下面是测试:

public class UserControllerTests {

    [Fact]
    public void GetAll_ReturnsObjectResult_WithAListOfUsers() {
        // Arrange
        var mockService = new Mock<IUserService>();
        var mockRequest = new Mock<IServiceRequest>();
        mockService.Setup(svc => svc.GetUsers(mockRequest.Object))
            .Returns(new ServiceRequest(new List<User> { new User() }));
        var controller = new UserController(mockService.Object);

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

        // Assert
        Assert.IsType<ObjectResult>(result);
        Assert.IsAssignableFrom<IEnumerable<User>>(((ObjectResult)result).Value);
    }

}

这是控制器:

public class UserController : Controller {

    private IUserService service;

    public UserController(IUserService service) {
        this.service = service;
    }

    [HttpGet]
    public IActionResult GetAll() {
        var req = new ServiceRequest();
        service.GetUsers(req);

        if(req.Errors != null) return new BadRequestObjectResult(req.Errors);
        return new ObjectResult(req.EntityCollection);
    }

}

和服务层:

public interface IUserService {
    IServiceRequest GetUsers(IServiceRequest req);
}    
public class UserService : IUserService {       
    private IUserRepository repo;       
    public IServiceRequest GetUsers(IServiceRequest req) {
        IEnumerable<User> users = null;         
        try {
            users = repo.GetAll();
        }
        catch(MySqlException ex) {
            req.AddError(new Error { Code = (int)ex.Number, Message = ex.Message });
        }
        finally {
            req.EntityCollection = users;
        }
        return req;
    }
}

public interface IServiceRequest {
    IEnumerable<Object> EntityCollection { get; set; }
    List<Error> Errors { get; }
    void AddError(Error error);
}
public class ServiceRequest : IServiceRequest {
    public IEnumerable<Object> EntityCollection { get; set; }
    public virtual List<Error> Errors { get; private set; }

    public ServiceRequest () { }

    public void AddError(Error error) {
        if(this.Errors == null) this.Errors = new List<Error>();
        this.Errors.Add(error);
    }       
}

就像我说的,这可能是我做错了什么,我在 mockService.Setup() 中思考,但我不确定在哪里。请帮忙?

service.GetUsers(req) 的使用来看,service 似乎应该填充服务请求,但在您的设置中,您让它返回了服务请求。根据您的代码也未使用的结果。

您需要 Callback 来填充提供给服务的任何参数,以便在调用时 mock/replicate。由于参数是在方法内部创建的,因此您将使用 Moq 的 It.IsAny<> 来允许模拟接受传递的任何参数。

var mockService = new Mock<IUserService>();
mockService.Setup(svc => svc.GetUsers(It.IsAny<IServiceRequest>()))
    .Callback((IServiceRequest arg) => {
        arg.EntityCollection = new List<User> { new User() };
    });

这应该允许被测方法通过它的调用并允许您断言结果。