问题
I am trying to unit test a method within my controller in my Web API using XUnit. The role of the method is to get a single title, by ISBN, from the database. The issue I came across during unit testing is that I am unsure how to insert the dummy data that I must perform the test on, as well as how the Assert function works.
TitleController.cs
[ApiController]
[Route("titlecontroller")]
public class TitleController : Controller
{
private IGtlTitleRepository _gtlTitleRepository;
public TitleController(IGtlTitleRepository gtlTitleRepository)
{
_gtlTitleRepository = gtlTitleRepository;
}
[Route("getTitle/{ISBN}")]
[HttpGet()]
public GtlTitle GetTitle(string ISBN)
{
return _gtlTitleRepository.GetTitle(ISBN);
}
}
IGtlTitleRepository.cs
public interface IGtlTitleRepository
{
GtlTitle GetTitle(string ISBN);
}
MockGtlTitleRepository.cs
public class MockGtlTitleRepository : IGtlTitleRepository
{
private readonly string _connection;
public MockGtlTitleRepository(IOptions<ConnectionStringList> connectionStrings)
{
_connection = connectionStrings.Value.GTLDatabase;
}
private List<GtlTitle> _titleList;
public GtlTitle GetTitle(string ISBN)
{
using (var connection = new SqlConnection(_connection))
{
connection.Open();
return connection.QuerySingle<GtlTitle>("GetTitleByISBN", new { ISBN }, commandType: CommandType.StoredProcedure);
}
}
}
Right, as for my test code, I was able to write the following code, but as I said above, I can't figure out a proper way to test the method.
public class UnitTest1
{
[Fact]
public void Test1()
{
var repositoryMock = new Mock<IGtlTitleRepository>();
var title = new GtlTitle();
repositoryMock.Setup(r => r.GetTitle("978-0-10074-5")).Returns(title);
var controller = new TitleController(repositoryMock.Object);
var result = controller.GetTitle("978-0-10074-5");
// assert??
repositoryMock.VerifyAll();
}
}
What should be done within this unit test in order to properly test the method?
EDIT:
GtlTitle.cs
public class GtlTitle
{
public string ISBN { get; set; }
public string VolumeName { get; set; }
public string TitleDescription { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PublisherName { get; set; }
}
回答1:
Before going to testing, there are a few things I recommend updating in your code:
- Make your repository methods and controller actions async (thus web server can process requests while waiting for database roundtrips for previous calls)
- Use
ActionResult
as an action return type. This way you can send different http status codes to the client. - Return 404 NotFound status code when title not found instead of returning successful result with
null
as payload. - Consider using a RESTful approach for API endpoints. E.g. base uri for titles resource should be something like
api/titles
- Don't specify
getTitle
for getting title endpoint, because you know HTTP verb which endpoint is mapped to (GET) and base resource url (api/titles).
With these notes applied:
[ApiController]
[Route("api/titles")]
public class TitleController : Controller
{
private IGtlTitleRepository _gtlTitleRepository;
public TitleController(IGtlTitleRepository gtlTitleRepository)
{
_gtlTitleRepository = gtlTitleRepository;
}
[HttpGet("{ISBN}")] // GET api/titles/{ISBN}
public async Task<ActionResult<GtlTitle>> GetTitle(string ISBN)
{
var title = await _gtlTitleRepository.GetTitle(ISBN);
if (title == null)
return NotFound();
return title;
}
}
Testing successful title retrieving:
[Fact]
public async Task Should_Return_Title_When_Title_Found()
{
var repositoryMock = new Mock<IGtlTitleRepository>();
var title = new GtlTitle();
repositoryMock.Setup(r => r.Get("978-0-10074-5")).Returns(Task.FromResult(title));
var controller = new TitleController(repositoryMock.Object);
var result = await controller.GetTitle("978-0-10074-5");
Assert.Equal(title, result.Value);
}
When title not found:
[Fact]
public async Task Should_Return_404_When_Title_Not_Found()
{
var repositoryMock = new Mock<IGtlTitleRepository>();
repositoryMock.Setup(r => r.Get("978-0-10074-5")).Returns(Task.FromResult<GtlTitle>(null));
var controller = new TitleController(repositoryMock.Object);
var result = await controller.GetTitle("978-0-10074-5");
Assert.IsType<NotFoundResult>(result.Result);
}
来源:https://stackoverflow.com/questions/61999456/how-to-unit-test-a-web-api-controller-using-xunit