【.NET Core】MSTestのチュートリアルをやってみる
概要
.NET Core 2.0がリリースされたのでMSTestのチュートリアルをやってみます。
ソリューションファイルの作成
$ mkdir unit-testing-using-dotnet-test $ cd unit-testing-using-dotnet-test/ $ $ dotnet new sln
ソリューションファイルの中身
$ cat unit-testing-using-dotnet-test.sln Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal
クラスライブラリプロジェクトの作成
$ mkdir PrimeService $ cd PrimeService/ $ dotnet new classlib
クラスライブラリプロジェクトファイルの中身
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> </Project>
PrimeServiceクラスの作成
■PrimeService/PrimeService.cs
$ mv Class1.cs PrimeService.cs
using System; namespace Prime.Services { public class PrimeService { public bool IsPrime(int candidate) { throw new NotImplementedException("Please create a test first"); } } }
クラスライブラリプロジェクトをソリューションに追加
$ cd ../
$ dotnet sln add PrimeService/PrimeService.csproj
テストプロジェクトの作成
MSTestのテンプレートを使用します。
$ mkdir PrimeService.Tests $ cd PrimeService.Tests/ $ dotnet new mstest
テストプロジェクトファイルの中身
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" /> <PackageReference Include="MSTest.TestAdapter" Version="1.1.18" /> <PackageReference Include="MSTest.TestFramework" Version="1.1.18" /> </ItemGroup> </Project>
クラスライブラリプロジェクトの参照追加
$ dotnet add reference ../PrimeService/PrimeService.csproj
テストプロジェクトをソリューションに追加
$ cd ../
$ dotnet sln add PrimeService.Tests/PrimeService.Tests.csproj
テストクラスの作成
■PrimeService.Tests/PrimeService_IsPrimeShould.cs
$ cd PrimeService.Tests/ $ mv UnitTest1.cs PrimeService_IsPrimeShould.cs
using Microsoft.VisualStudio.TestTools.UnitTesting; using Prime.Services; namespace Prime.UnitTests.Services { [TestClass] public class PrimeService_IsPrimeShould { private readonly PrimeService _primeService; public PrimeService_IsPrimeShould() { _primeService = new PrimeService(); } [TestMethod] public void ReturnFalseGivenValueOf1() { var result = _primeService.IsPrime(1); Assert.IsFalse(result,"1 should not be prime"); } } }
クラスライブラリプロジェクトのビルド
コンソールにはビルド結果が以下のような感じで出力されました。
$ cd ../PrimeService $ dotnet build .NET Core 向け Microsoft (R) Build Engine バージョン 15.3.409.57025 Copyright (C) Microsoft Corporation.All rights reserved. PrimeService -> /Users/soil/src/github/unit-testing-using-dotnet-test/PrimeService/bin/Debug/netstandard2.0/PrimeService.dll ビルドに成功しました。 0 個の警告 0 エラー 経過時間 00:00:02.03
単体テストの実行
テストプロジェクト側に戻ってテストを実行します。
$ cd ../PrimeService.Tests/ $ dotnet test Build started, please wait... Build completed. Test run for /Users/soil/src/github/unit-testing-using-dotnet-test/PrimeService.Tests/bin/Debug/netcoreapp2.0/PrimeService.Tests.dll(.NETCoreApp,Version=v2.0) Microsoft (R) Test Execution Command Line Tool Version 15.3.0-preview-20170628-02 Copyright (c) Microsoft Corporation. All rights reserved. テスト実行を開始しています。お待ちください... 失敗 Prime.UnitTests.Services.PrimeService_IsPrimeShould.ReturnFalseGivenValueOf1 エラー メッセージ: Test method Prime.UnitTests.Services.PrimeService_IsPrimeShould.ReturnFalseGivenValueOf1 threw exception: System.NotImplementedException: Please create a test first スタック トレース: at Prime.Services.PrimeService.IsPrime(Int32 candidate) in /Users/soil/src/github/unit-testing-using-dotnet-test/PrimeService/PrimeService.cs:line 9 at Prime.UnitTests.Services.PrimeService_IsPrimeShould.ReturnFalseGivenValueOf1() in /Users/soil/src/github/unit-testing-using-dotnet-test/PrimeService.Tests/PrimeService_IsPrimeShould.cs:line 19 テストの合計数: 1。成功: 0。失敗:1。スキップ: 0。 テストの実行に失敗しました。 テスト実行時間: 3.0107 秒
失敗します。
PrimeServiceクラスを修正しましょう。
■PrimeService/PrimeService.cs
using System; namespace Prime.Services { public class PrimeService { public bool IsPrime(int candidate) { if (candidate == 1) { return false; } throw new NotImplementedException("Please create a test first"); } } }
再度クラスライブラリプロジェクトをビルドしてテストを実行するとテストが成功しました。
$ dotnet test Build started, please wait... Build completed. Test run for /Users/soil/src/github/unit-testing-using-dotnet-test/PrimeService.Tests/bin/Debug/netcoreapp2.0/PrimeService.Tests.dll(.NETCoreApp,Version=v2.0) Microsoft (R) Test Execution Command Line Tool Version 15.3.0-preview-20170628-02 Copyright (c) Microsoft Corporation. All rights reserved. テスト実行を開始しています。お待ちください... テストの合計数: 1。成功: 1。失敗:0。スキップ: 0。 テストの実行に成功しました。 テスト実行時間: 2.2823 秒
次回はこれをベースに、前回のMoqのquickstartの続きをやってみようと思います。
【C#】MoqのQuickstartをやってみる
参考
https://github.com/Moq/moq4/wiki/Quickstart
Methods
まずはこの辺のメソッドを押さえておけばいいのかな。
- Returns
- Throws
- Callback
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; namespace MoqQuickStart { [TestClass] public class Methods { [TestMethod] public void Practice() { var mock = new Mock<IFoo>(); mock.Setup(foo => foo.DoSomething("ping")).Returns(true); var f = mock.Object; Assert.IsFalse(f.DoSomething("pong")); Assert.IsTrue(f.DoSomething("ping")); } [TestMethod] public void Out_argument() { var outString = "ack"; var mock = new Mock<IFoo>(); mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true); var f = mock.Object; Assert.IsFalse(f.TryParse("pong", out outString)); Assert.IsTrue(f.TryParse("ping", out outString)); } [TestMethod] public void Ref_argument() { var instance = new Bar(); var mock = new Mock<IFoo>(); mock.Setup(foo => foo.Submit(ref instance)).Returns(true); var f = mock.Object; Assert.IsTrue(f.Submit(ref instance)); } [TestMethod] public void Access_invocation_arguments_when_returning_a_value() { var mock = new Mock<IFoo>(); mock.Setup(x => x.DoSomethingStringy(It.IsAny<string>())) .Returns((string s) => s.ToLower()); var f = mock.Object; var actual = f.DoSomethingStringy("HOGE"); Assert.AreEqual("hoge", actual); } [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void Throwing_when_invoked_with_specific_parameters_1() { var mock = new Mock<IFoo>(); mock.Setup(foo => foo.DoSomething("reset")).Throws<InvalidOperationException>(); mock.Object.DoSomething("reset"); Assert.Fail(); } [TestMethod] public void Throwing_when_invoked_with_specific_parameters_2() { var mock = new Mock<IFoo>(); mock.Setup(foo => foo.DoSomething("")).Throws(new ArgumentException("command")); try { mock.Object.DoSomething(""); Assert.Fail(); } catch (ArgumentException ex) { Assert.AreEqual("command",ex.Message); } } [TestMethod] public void Lazy_evaluating_return_value() { var count = 1; var mock = new Mock<IFoo>(); mock.Setup(foo => foo.GetCount()).Returns(() => count); var actual = mock.Object.GetCount(); Assert.AreEqual(1, actual); } [TestMethod] public void Returning_different_values_on_each_invocation() { var mock = new Mock<IFoo>(); var calls = 0; mock.Setup(foo => foo.GetCount()) .Returns(() => calls) .Callback(() => calls++); Console.WriteLine(mock.Object.GetCount()); Assert.AreEqual(1, calls); Console.WriteLine(mock.Object.GetCount()); Assert.AreEqual(2, calls); } } }