C# 如何使用Moq和Nunit测试ASP.NETMVC POST控制器

C# 如何使用Moq和Nunit测试ASP.NETMVC POST控制器,c#,asp.net-mvc,unit-testing,nunit,moq,C#,Asp.net Mvc,Unit Testing,Nunit,Moq,我想编写一个单元测试来测试是否创建了一个新项,而不实际将它持久化到数据库中。我不太熟悉Moq,也不太熟悉一般的嘲笑 以下是控制器代码: // POST: api/MoviesAPI [ResponseType(typeof(MovieDTO))] [Route("api/movies/post")] public IHttpActionResult PostMovies(MovieDTO movie) { // Validation if (String.IsNullOrWhi

我想编写一个单元测试来测试是否创建了一个新项,而不实际将它持久化到数据库中。我不太熟悉Moq,也不太熟悉一般的嘲笑

以下是控制器代码:

// 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);
    }
}
//POST:api/MoviesAPI
[ResponseType(typeof(MovieDTO))]
[路线(“api/movies/post”)]
公共IHttpActionResult PostMovies(电影到电影)
{
//验证
if(String.IsNullOrWhiteSpace(movie.Title))
{
返回Ok(“需要电影标题”);
}
if(movie.GenreIds==null | | movie.GenreIds.Count==0)
{
返回Ok(“新电影需要至少选择一种类型”);
}
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
///验证
////创建要添加的电影类型对象
var newMovie=新电影()
{
标题=电影。标题,
发行的,发行的
};
使用(var db=new MoviesContext())
{
//将DB中的类型链接到新电影
newMovie.Genres=新列表();
foreach(电影中的变量g.GenreIds)
{
var genreToAdd=db.Genres.FirstOrDefault(x=>x.GenreId==g);
newMovie.Genres.Add(流派重新加载);
}
//尝试插入新电影
尝试
{
db.Movies.Add(newMovie);
db.SaveChanges();
}
捕获(DbEntityValidationException ex)
{
返回请求(例如消息);
}
返回Ok(电影);
}
}
还有我的不完全测试:

[TestMethod]
public void Insert_NewMovie_IsSuccessful()
{
    //var sut = new Mock<MoviesAPIController>();
    var sut = new MoviesAPIController();
    var model = new MovieDTO();

    //sut.PostMovies(model);

    // TODO: Assert
}
[TestMethod]
public void Insert_NewMovie_issessful()
{
//var sut=new Mock();
var sut=新的MoviesApicController();
var模型=新电影到();
//sut.PostMovies(模型);
//待办事项:断言
}

除了建议的注释,您还应该查看以下资源

最后一个链接只是我用来获取之前链接的谷歌搜索

如果您花时间查看提供的链接,您将更好地了解如何编写单元测试来测试是否创建了新项,而不实际将其持久化到数据库中

下面的示例是根据上面的链接建模的,并进行了修改,以显示如何根据提供的代码执行此操作

这里是一个简化的控制器,您的所有db代码都已分离出来,成为它自己的关注点

[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);
    } 
}
这是一个帖子的示例测试,再次根据您原来的示例进行了修改

[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"]);
}
[TestMethod]
public void PostMethodSetsLocationHeader()
{
//安排
var mockRepository=new Mock();
var controller=new MoviesAPIController(mockRepository.Object);
var模型=新电影到()
{
Title=“疯狂麦克斯:愤怒之路”,
Released=DateTime.Parse(“2015年5月15日”),
GenreIds=新列表(){1}
};
//表演
IHttpActionResult actionResult=控制器。后期移动(模型);
var createdResult=actionResult作为createDatRouteneGottatedContentResult;
//断言
Assert.IsNotNull(createdResult);
AreEqual(“DefaultApi”,createdResult.RouteName);
Assert.AreEqual(model.Title,createdResult.RouteValues[“Title”]);
}

首先,您必须将所有db代码移出控制器。将其添加到具有接口的类中,然后将其注入控制器构造函数。您必须拆分代码层。添加服务层和数据层将允许您使用模拟服务对您的业务逻辑进行单元测试感谢您在回答中付出的努力和周到。我还建议将验证移出控制器