控制器 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() };
});
这应该允许被测方法通过它的调用并允许您断言结果。
我是单元测试的新手,所以我的问题可能出在我的代码上,而不是 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() };
});
这应该允许被测方法通过它的调用并允许您断言结果。