.NET Core之單元測試(三):Mock框架Moq的使用
阿新 • • 發佈:2020-02-23
編寫一個API
新增一個介面
public interface IFoo
{
bool Ping(string ip);
}
介面實現
public class Foo : IFoo
{
public bool Ping(string ip)
{
return new Random().Next(1, 100) % 2 == 1;
}
}
編寫一個待測試的API,其中有三個依賴項:SqliteDbContext
,ILogger<SampleController>
和IFoo
API實現的功能:先獲取SqliteDbContext中的SampleEntity,如果其中的屬性StringValue值為ping,並且結果為False,則返回404
[Route("api/[controller]")] [ApiController] public class SampleController : ControllerBase { private readonly SqliteDbContext _sqliteDbContext; private readonly ILogger<SampleController> _logger; private readonly IFoo _foo; public SampleController(SqliteDbContext sqliteDbContext, ILogger<SampleController> logger,IFoo foo) { _logger = logger; _sqliteDbContext = sqliteDbContext; } [HttpGet("{id}")] public async Task<IActionResult> Get(int id) { var sampleData = await _sqliteDbContext.SampleEntity .SingleOrDefaultAsync(s => s.Id == id); if (sampleData?.StringValue == "ping") { var pingOk = _foo.Ping("localhost"); if (!pingOk) return NotFound(); } return Ok(sampleData); } }
測試用例
- Mock
ILogger<SampleController>
var loggerMock = new Mock<ILogger<SampleController>>();
var logger = loggerMock.Object;
- Mock
Ping(string ip)
var fooMock = new Mock<IFoo>();
fooMock.Setup(foo => foo.Ping("localhost")).Returns(true);
var foo = fooMock.Object;
關於
Moq
的更多操作可參見:Moq4 Quickstart
- 修改
GetSqliteDbContextAsync()
,新增一個ID為2的資料記錄
private async Task<SqliteDbContext> GetSqliteDbContextAsync()
{
var options = new DbContextOptionsBuilder<SqliteDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var sqliteDbContext = new SqliteDbContext(options);
sqliteDbContext.SampleEntity.Add(new Infrastructure.Entities.SampleEntity
{
Id = 1,
BoolValue = false,
DateTimeValue = DateTime.Now,
StringValue = "sample"
});
sqliteDbContext.SampleEntity.Add(new Infrastructure.Entities.SampleEntity
{
Id = 2,
BoolValue = false,
DateTimeValue = DateTime.Now,
StringValue = "ping"
});
await sqliteDbContext.SaveChangesAsync();
return sqliteDbContext;
}
- 測試
Ping==True
[TestMethod]
public async Task Get_ReturnOK_WithPingTrue()
{
// Arrange
var dbContext = await GetSqliteDbContextAsync();
var loggerMock = new Mock<ILogger<SampleController>>();
var logger = loggerMock.Object;
var fooMock = new Mock<IFoo>();
fooMock.Setup(foo => foo.Ping("localhost")).Returns(true);
var foo = fooMock.Object;
var controller = new SampleController(dbContext, logger, foo);
// Act
var response = await controller.Get(2);
var responseModel = ((OkObjectResult)response).Value as SampleEntity;
// Assert
Assert.IsInstanceOfType(response, typeof(OkObjectResult));
Assert.IsTrue(responseModel.Id == 2);
Assert.IsFalse(responseModel.BoolValue);
Assert.IsTrue(responseModel.StringValue == "ping");
}
- 測試
Ping==False
[TestMethod]
public async Task Get_ReturnOK_WithPingFalse()
{
// Arrange
var dbContext = await GetSqliteDbContextAsync();
var loggerMock = new Mock<ILogger<SampleController>>();
var logger = loggerMock.Object;
var fooMock = new Mock<IFoo>();
fooMock.Setup(foo => foo.Ping("localhost")).Returns(false);
var foo = fooMock.Object;
var controller = new SampleController(dbContext, logger, foo);
// Act
var response = await controller.Get(2);
// Assert
Assert.IsInstanceOfType(response, typeof(NotFoundResult));
}
- 測試結果