單元測試的特性跟優點在這邊就不贅述了,有興趣的可以參考官方文件,或者去上 91 大大的課。今天的重點會擺在如何在 ASP.NET Core MVC 專案中建立單元測試。.NET 有幾套主流的 test framework:xUnit、NUnit 和 MSTest,今天會以 MSTest
來作介紹。
可以用 dotnet CLI
指定來建立:
dotnet new mstest --output ironman2018.Tests
dotnet new mstest -o ironman2018.Tests
cd ironman2018.Tests
dotnet add reference ../ironman2018/ironman2018.csproj
或者在 VS 2017 裡面建立:
.Tests
來命名。ironman2018.Tests
專案中的參考點「右鍵 > 加入參考」。ironman2018
。建立完測試專案後,按 ctrl + R, A
就可以執行全部的測試了。因為剛建立只有一個沒做檢查的測試,會看到測試全部通過XD
Controller 單元測試的重點應該在 Controller 中的行為或是否有回傳正確結果(與 View 無關)。例如我們測試下面這個 Controller:
public class HomeController : Controller
{
private readonly ITodoRepository _todoRepository;
public HomeController(ITodoRepository todoRepository)
{
_todoRepository = todoRepository;
}
public IActionResult Index()
{
var todos = _todoRepository.GetAll().ToList();
return View(todos);
}
}
其中有使用 Repository
模式來隔離資料介面,方便我們做測試。ITodoRepository
的介面定義:
public interface ITodoRepository : IDisposable
{
void Insert(TodoModel instance);
void Update(TodoModel instance);
void Delete(TodoModel instance);
TodoModel Get(Expression<Func<TodoModel, bool>> predicate);
IQueryable<TodoModel> GetAll();
void SaveChanges();
}
接下來預期對 TodoController.Index()
測試三個項目:
ViewResult
。ViewDataDictionary.Model
的類別是 TodoModel
。ViewDataDictionary.Model
中有兩筆資料。除了原本參考的
MSTest
外,這邊還有參考額外兩個 Library:
NSubstitute
:用來做 mockFluentAssertions
:讓 assert 比較好閱讀,而且 MSTest 的 assert 方法比較少
完整的測試類別如下:
[TestClass]
public class TodoHomeControllerTests
{
private HomeController todoController;
[TestInitialize]
public void SetUp()
{
ITodoRepository mockRepository = Substitute.For<ITodoRepository>();
mockRepository.GetAll().Returns(new List<TodoModel>
{
new TodoModel
{
Title = "dotnet Core",
CreatedAt = DateTime.Now,
Completed = true
},
new TodoModel
{
Title = "unit test",
CreatedAt = DateTime.Now,
Completed = false
},
}.AsQueryable());
todoController = new HomeController(mockRepository);
}
[TestMethod]
public void Test_Index_Return_ViewResult_With_TodoModel()
{
// arrange
// act
var result = todoController.Index();
// assert
var okResult = result.Should()
.BeOfType<ViewResult>().Subject;
var todos = okResult.ViewData.Model.Should()
.BeAssignableTo<IEnumerable<TodoModel>>().Subject;
todos.Count().Should().Be(2);
}
}
最後再按下 ctrl + R, A
,就可以看到測試成功的畫面了!