我如何使用 Moq 和 Nunit 测试 ASP.Net MVC POST 控制器
How can I test ASP.Net MVC POST Controller with Moq and Nunit
我想编写一个单元测试来测试是否创建了一个新项目,而不是将其实际保存到数据库中。我对Moq不是很熟悉,或者说是一般的mocking。
控制器代码如下:
// POST: api/MoviesAPI
[ResponseType(typeof(MovieDTO))]
[Route("api/movies/post")]
public IHttpActionResult PostMovies(MovieDTO movie)
{
// Validation
if (String.IsNullOrWhiteSpace(movie.Title))
{
return Ok("Movie Title is required");
}
if (movie.GenreIds == null || movie.GenreIds.Count == 0)
{
return Ok("A new Movie requires at least one genre to be selected");
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// /Validation
//// Create Movie type object to add
var newMovie = new Movies()
{
Title = movie.Title,
Released = movie.Released
};
using (var db = new MoviesContext())
{
// Link genres from DB to the new Movie
newMovie.Genres = new List<Genres>();
foreach (var g in movie.GenreIds)
{
var genreToAdd = db.Genres.FirstOrDefault(x => x.GenreId == g);
newMovie.Genres.Add(genreToAdd);
}
// Try to insert the new Movie
try
{
db.Movies.Add(newMovie);
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
return BadRequest(ex.Message);
}
return Ok(movie);
}
}
还有我未完成的测试:
[TestMethod]
public void Insert_NewMovie_IsSuccessful()
{
//var sut = new Mock<MoviesAPIController>();
var sut = new MoviesAPIController();
var model = new MovieDTO();
//sut.PostMovies(model);
// TODO: Assert
}
除了建议的评论之外,您还应该查看以下资源
Unit Testing Controllers in ASP.NET Web API 2
C# Writing unit tests with NUnit and Moq
Writing unit tests with NUnit and Moq
最后一个 link 就是我用来获取之前的那些的 Google 搜索。 :)
如果您花时间复习 link,您将更好地了解如何编写单元测试来测试是否创建了新项目,而无需将其实际保存到数据库中
以下示例是根据上面的 link 建模并进行修改以显示如何根据提供的代码执行此操作。
这是一个简化的控制器,其中您的所有数据库代码都已分离到它自己的关注中。
[RoutePrefix("api/movies")]
public class MoviesAPIController : ApiController {
IMovieRepository repository;
public MovieController(IMovieRepository repository) {
this.repository = repository;
}
[HttpGet]
[Route("")]
[ResponseType(typeof(MovieDTO))]
public IHttpActionResult Get(int id) {
var movie = repository.GetById(id);
if (movie == null) {
return NotFound();
}
return Ok(movie);
}
// POST api/movies
[HttpPost]
[Route("")]
[ResponseType(typeof(MovieDTO))]
public IHttpActionResult PostMovies(MovieDTO movie) {
// Validation
if (String.IsNullOrWhiteSpace(movie.Title)) {
return BadRequest("Movie Title is required");
}
if (movie.GenreIds == null || movie.GenreIds.Count == 0) {
return BadRequest("A new Movie requires at least one genre to be selected");
}
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
repository.Add(movie);
return CreatedAtRoute("DefaultApi", new { id = movie.Id, title = movie.Title }, movie);
}
public IHttpActionResult Delete(int id) {
repository.Delete(id);
return Ok();
}
public IHttpActionResult Put(MovieDTO movie) {
// Do some work (not shown).
return Content(HttpStatusCode.Accepted, movie);
}
}
这里是 POST 的示例测试,再次根据您的原始示例进行了修改。
[TestMethod]
public void PostMethodSetsLocationHeader()
{
// Arrange
var mockRepository = new Mock<IMovieRepository>();
var controller = new MoviesAPIController(mockRepository.Object);
var model = new MovieDTO()
{
Title = "Mad Max: Fury Road",
Released = DateTime.Parse("15 May 2015"),
GenreIds = new List<int>(){ 1 }
};
// Act
IHttpActionResult actionResult = controller.PostMovies(model);
var createdResult = actionResult as CreatedAtRouteNegotiatedContentResult<MovieDTO>;
// Assert
Assert.IsNotNull(createdResult);
Assert.AreEqual("DefaultApi", createdResult.RouteName);
Assert.AreEqual(model.Title, createdResult.RouteValues["title"]);
}
我想编写一个单元测试来测试是否创建了一个新项目,而不是将其实际保存到数据库中。我对Moq不是很熟悉,或者说是一般的mocking。
控制器代码如下:
// POST: api/MoviesAPI
[ResponseType(typeof(MovieDTO))]
[Route("api/movies/post")]
public IHttpActionResult PostMovies(MovieDTO movie)
{
// Validation
if (String.IsNullOrWhiteSpace(movie.Title))
{
return Ok("Movie Title is required");
}
if (movie.GenreIds == null || movie.GenreIds.Count == 0)
{
return Ok("A new Movie requires at least one genre to be selected");
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// /Validation
//// Create Movie type object to add
var newMovie = new Movies()
{
Title = movie.Title,
Released = movie.Released
};
using (var db = new MoviesContext())
{
// Link genres from DB to the new Movie
newMovie.Genres = new List<Genres>();
foreach (var g in movie.GenreIds)
{
var genreToAdd = db.Genres.FirstOrDefault(x => x.GenreId == g);
newMovie.Genres.Add(genreToAdd);
}
// Try to insert the new Movie
try
{
db.Movies.Add(newMovie);
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
return BadRequest(ex.Message);
}
return Ok(movie);
}
}
还有我未完成的测试:
[TestMethod]
public void Insert_NewMovie_IsSuccessful()
{
//var sut = new Mock<MoviesAPIController>();
var sut = new MoviesAPIController();
var model = new MovieDTO();
//sut.PostMovies(model);
// TODO: Assert
}
除了建议的评论之外,您还应该查看以下资源
Unit Testing Controllers in ASP.NET Web API 2
C# Writing unit tests with NUnit and Moq
Writing unit tests with NUnit and Moq
最后一个 link 就是我用来获取之前的那些的 Google 搜索。 :)
如果您花时间复习 link,您将更好地了解如何编写单元测试来测试是否创建了新项目,而无需将其实际保存到数据库中
以下示例是根据上面的 link 建模并进行修改以显示如何根据提供的代码执行此操作。
这是一个简化的控制器,其中您的所有数据库代码都已分离到它自己的关注中。
[RoutePrefix("api/movies")]
public class MoviesAPIController : ApiController {
IMovieRepository repository;
public MovieController(IMovieRepository repository) {
this.repository = repository;
}
[HttpGet]
[Route("")]
[ResponseType(typeof(MovieDTO))]
public IHttpActionResult Get(int id) {
var movie = repository.GetById(id);
if (movie == null) {
return NotFound();
}
return Ok(movie);
}
// POST api/movies
[HttpPost]
[Route("")]
[ResponseType(typeof(MovieDTO))]
public IHttpActionResult PostMovies(MovieDTO movie) {
// Validation
if (String.IsNullOrWhiteSpace(movie.Title)) {
return BadRequest("Movie Title is required");
}
if (movie.GenreIds == null || movie.GenreIds.Count == 0) {
return BadRequest("A new Movie requires at least one genre to be selected");
}
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
repository.Add(movie);
return CreatedAtRoute("DefaultApi", new { id = movie.Id, title = movie.Title }, movie);
}
public IHttpActionResult Delete(int id) {
repository.Delete(id);
return Ok();
}
public IHttpActionResult Put(MovieDTO movie) {
// Do some work (not shown).
return Content(HttpStatusCode.Accepted, movie);
}
}
这里是 POST 的示例测试,再次根据您的原始示例进行了修改。
[TestMethod]
public void PostMethodSetsLocationHeader()
{
// Arrange
var mockRepository = new Mock<IMovieRepository>();
var controller = new MoviesAPIController(mockRepository.Object);
var model = new MovieDTO()
{
Title = "Mad Max: Fury Road",
Released = DateTime.Parse("15 May 2015"),
GenreIds = new List<int>(){ 1 }
};
// Act
IHttpActionResult actionResult = controller.PostMovies(model);
var createdResult = actionResult as CreatedAtRouteNegotiatedContentResult<MovieDTO>;
// Assert
Assert.IsNotNull(createdResult);
Assert.AreEqual("DefaultApi", createdResult.RouteName);
Assert.AreEqual(model.Title, createdResult.RouteValues["title"]);
}