简体   繁体   中英

Controller API Testing with xUnit/Moq - Controller is null

I'm new to unit testing, so my problem is probably with my code and not the Moq framework, but here goes.

I'm using .Net Core with xUnit and the Moq framework, and I'm more or less following instructions from their documentation . I'm trying to test route api/user to get all users, and the issue was on asserting that the response was an ObjectResult containing <IEnumerable<User>> . No matter what I tried, result.Value was always null. The first assertion passes fine.

I set up a console project to debug this, and found something interesting. that value of the controller in the test method in Visual Studio is null. In VS Code, the value in the debugger shows Unknown Error: 0x00000... .

Below is the test:

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);
    }

}

And here is the controller:

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);
    }

}

And the Service Layer:

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);
    }       
}

Like I said, it's probably something I'm doing wrong, I'm thinking in the mockService.Setup() but I'm not sure where. Help please?

From the use of service.GetUsers(req) it looks like service is suppose to populate the service request but in your setup you have it returning a service request. A result which is also not used according to your code.

You need a Callback to populate whatever parameter is given to the service in order to mock/replicate when it is invoked. Since the parameter is being created inside of the method you will use Moq's It.IsAny<> to allow the mock to accept any parameter that is passed.

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

This should allow the method under test to flow through it's invocation and allow you to assert the outcome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM