单元测试 - 以列表作为数据存储的模拟服务
Unit testing - mocking service which has a List as a data storage
我是单元测试的新手,我正在努力学习如何做。
我正在使用 Moq 来模拟依赖项。
这是我的测试 class:
using Microsoft.AspNetCore.Mvc;
using Moq;
using scholarship.Controllers;
using scholarship.Services.Interface;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using Xunit;
namespace Testing
{
public class InternControllerTests
{
private Mock<IInternService> _internService = new Mock<IInternService>();
[Theory]
[InlineData("00000000-0000-0000-0000-000000000001")]
[InlineData("00000000-0000-0000-0000-000000000002")]
public void Delete_Intern(Guid id)
{
InternsController internsController
= new InternsController(_internService.Object);
var actual = internsController.DeleteIntern(id) as ObjectResult;
Assert.True(actual is OkObjectResult);
}
[Theory]
[InlineData("00000000-0000-0000-0000-000000000000")]
[InlineData("00000000-0000-0000-0000-000000000005")]
public void Delete_Intern_NotFound(Guid id)
{
InternsController internsController
= new InternsController(_internService.Object);
var actual = internsController.DeleteIntern(id) as ObjectResult;
Assert.True(actual is NotFoundObjectResult);
}
}
}
服务:
using scholarship.Models;
using scholarship.Services.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace scholarship.Services.Class
{
public class InternCollectionService : IInternService
{
public static List<Intern> _interns = new List<Intern>
{
new Intern { ID = new Guid("00000000-0000-0000-0000-000000000001"), FirstName = "Octavian", LastName = "Niculescu", DateOfBirth=new DateTime(2001,01,01)},
new Intern { ID = new Guid("00000000-0000-0000-0000-000000000002"), FirstName = "Andrei", LastName = "Popescu", DateOfBirth=new DateTime(2002,01,01)},
new Intern { ID = new Guid("00000000-0000-0000-0000-000000000003"), FirstName = "Calin", LastName = "David", DateOfBirth=new DateTime(2003,01,01)},
};
public bool Create(Intern model)
{
_interns.Add(model);
return true;
}
public bool Delete(Guid id)
{
int index = _interns.FindIndex(intern => intern.ID == id);
if (index == -1)
{
return false;
}
_interns.RemoveAt(index);
return true;
}
public Intern Get(Guid id)
{
return (from intern in _interns
where intern.ID == id
select intern).FirstOrDefault();
}
public List<Intern> GetAll()
{
return _interns;
}
public bool Update(Guid id, Intern model)
{
int index = _interns.FindIndex(intern => intern.ID == id);
if (index == -1)
{
return false;
}
model.ID = id;
_interns[index] = model;
return true;
}
}
}
控制器
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using scholarship.Models;
using scholarship.Services.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace scholarship.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class InternsController : ControllerBase
{
IInternService _internService;
public InternsController(IInternService internService)
{
_internService = internService ?? throw new ArgumentNullException(nameof(internService));
}
[HttpGet]
public IActionResult GetInterns()
{
return Ok(_internService.GetAll());
}
[HttpGet("{Id}", Name = "GetIntern")]
public IActionResult GetIntern([FromRoute] Guid Id)
{
Intern? intern = _internService.Get(Id);
if(intern == null)
{
return NotFound();
}
return Ok(intern);
}
[HttpPost]
public IActionResult AddIntern([FromBody] Intern intern)
{
intern.ID = Guid.NewGuid();
_internService.Create(intern);
return CreatedAtRoute("GetIntern", new { ID = intern.ID }, intern);
}
[HttpPut("{id}")]
public IActionResult UpdateIntern([FromBody] Intern intern, Guid id)
{
if (intern == null)
{
return BadRequest("Intern cannot be null");
}
_internService.Update(id, intern);
return Ok();
}
[HttpDelete("{id}")]
public IActionResult DeleteIntern(Guid id)
{
bool deleted = _internService.Delete(id);
if (deleted == false)
{
return NotFound("Intern cannot be found");
}
return Ok();
}
}
}
项目很小,我用它来开始学习.net
现在想学习单元测试,正在努力学习单元测试
删除测试失败。
我认为发生这种情况是因为通过模拟服务,没有像服务中那样包含数据的列表。
那么,我应该如何进行删除测试呢?我是否也应该以某种方式嘲笑该列表? (我不知道如何)
谢谢。
虽然一次性测试所有内容并不是最佳做法,但您可以按照以下更改代码并使用内联数据和硬编码 return 类型通过状态代码进行测试:
[Theory]
[InlineData("00000000-0000-0000-0000-000000000001", true, 200)]
[InlineData("00000000-0000-0000-0000-000000000002", true, 200)]
[InlineData("00000000-0000-0000-0000-000000000000", false, 404)]
[InlineData("00000000-0000-0000-0000-000000000005", false, 404)]
public void Delete_Intern(Guid id, bool expectedReturn, int expectedStatusCode)
{
InternsController internsController
= new InternsController(_internService.Object);
_internService.Setup(x => x.Delete(It.Is<Guid>(x => x.Equals(id)))).Returns(expectedReturn);
var actual = internsController.DeleteIntern(id) as ObjectResult;
Assert.True(actual.StatusCode == expectedStatusCode);
}
但是,您可以阅读 How to use Moq and xUnit for Unit Testing Controllers in ASP.NET Core 我认为这是一个很好的做法。
我是单元测试的新手,我正在努力学习如何做。
我正在使用 Moq 来模拟依赖项。
这是我的测试 class:
using Microsoft.AspNetCore.Mvc;
using Moq;
using scholarship.Controllers;
using scholarship.Services.Interface;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using Xunit;
namespace Testing
{
public class InternControllerTests
{
private Mock<IInternService> _internService = new Mock<IInternService>();
[Theory]
[InlineData("00000000-0000-0000-0000-000000000001")]
[InlineData("00000000-0000-0000-0000-000000000002")]
public void Delete_Intern(Guid id)
{
InternsController internsController
= new InternsController(_internService.Object);
var actual = internsController.DeleteIntern(id) as ObjectResult;
Assert.True(actual is OkObjectResult);
}
[Theory]
[InlineData("00000000-0000-0000-0000-000000000000")]
[InlineData("00000000-0000-0000-0000-000000000005")]
public void Delete_Intern_NotFound(Guid id)
{
InternsController internsController
= new InternsController(_internService.Object);
var actual = internsController.DeleteIntern(id) as ObjectResult;
Assert.True(actual is NotFoundObjectResult);
}
}
}
服务:
using scholarship.Models;
using scholarship.Services.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace scholarship.Services.Class
{
public class InternCollectionService : IInternService
{
public static List<Intern> _interns = new List<Intern>
{
new Intern { ID = new Guid("00000000-0000-0000-0000-000000000001"), FirstName = "Octavian", LastName = "Niculescu", DateOfBirth=new DateTime(2001,01,01)},
new Intern { ID = new Guid("00000000-0000-0000-0000-000000000002"), FirstName = "Andrei", LastName = "Popescu", DateOfBirth=new DateTime(2002,01,01)},
new Intern { ID = new Guid("00000000-0000-0000-0000-000000000003"), FirstName = "Calin", LastName = "David", DateOfBirth=new DateTime(2003,01,01)},
};
public bool Create(Intern model)
{
_interns.Add(model);
return true;
}
public bool Delete(Guid id)
{
int index = _interns.FindIndex(intern => intern.ID == id);
if (index == -1)
{
return false;
}
_interns.RemoveAt(index);
return true;
}
public Intern Get(Guid id)
{
return (from intern in _interns
where intern.ID == id
select intern).FirstOrDefault();
}
public List<Intern> GetAll()
{
return _interns;
}
public bool Update(Guid id, Intern model)
{
int index = _interns.FindIndex(intern => intern.ID == id);
if (index == -1)
{
return false;
}
model.ID = id;
_interns[index] = model;
return true;
}
}
}
控制器
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using scholarship.Models;
using scholarship.Services.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace scholarship.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class InternsController : ControllerBase
{
IInternService _internService;
public InternsController(IInternService internService)
{
_internService = internService ?? throw new ArgumentNullException(nameof(internService));
}
[HttpGet]
public IActionResult GetInterns()
{
return Ok(_internService.GetAll());
}
[HttpGet("{Id}", Name = "GetIntern")]
public IActionResult GetIntern([FromRoute] Guid Id)
{
Intern? intern = _internService.Get(Id);
if(intern == null)
{
return NotFound();
}
return Ok(intern);
}
[HttpPost]
public IActionResult AddIntern([FromBody] Intern intern)
{
intern.ID = Guid.NewGuid();
_internService.Create(intern);
return CreatedAtRoute("GetIntern", new { ID = intern.ID }, intern);
}
[HttpPut("{id}")]
public IActionResult UpdateIntern([FromBody] Intern intern, Guid id)
{
if (intern == null)
{
return BadRequest("Intern cannot be null");
}
_internService.Update(id, intern);
return Ok();
}
[HttpDelete("{id}")]
public IActionResult DeleteIntern(Guid id)
{
bool deleted = _internService.Delete(id);
if (deleted == false)
{
return NotFound("Intern cannot be found");
}
return Ok();
}
}
}
项目很小,我用它来开始学习.net
现在想学习单元测试,正在努力学习单元测试
删除测试失败。
我认为发生这种情况是因为通过模拟服务,没有像服务中那样包含数据的列表。
那么,我应该如何进行删除测试呢?我是否也应该以某种方式嘲笑该列表? (我不知道如何)
谢谢。
虽然一次性测试所有内容并不是最佳做法,但您可以按照以下更改代码并使用内联数据和硬编码 return 类型通过状态代码进行测试:
[Theory]
[InlineData("00000000-0000-0000-0000-000000000001", true, 200)]
[InlineData("00000000-0000-0000-0000-000000000002", true, 200)]
[InlineData("00000000-0000-0000-0000-000000000000", false, 404)]
[InlineData("00000000-0000-0000-0000-000000000005", false, 404)]
public void Delete_Intern(Guid id, bool expectedReturn, int expectedStatusCode)
{
InternsController internsController
= new InternsController(_internService.Object);
_internService.Setup(x => x.Delete(It.Is<Guid>(x => x.Equals(id)))).Returns(expectedReturn);
var actual = internsController.DeleteIntern(id) as ObjectResult;
Assert.True(actual.StatusCode == expectedStatusCode);
}
但是,您可以阅读 How to use Moq and xUnit for Unit Testing Controllers in ASP.NET Core 我认为这是一个很好的做法。