VisualStudio のテスト
◆ MSTest
VisualStudio のメニューバーに 「テスト」 ってありますよね
メニューにあれこれありすぎて使っていないのが多いですけど今回はこれを使ってみます
例えばこういうコード書いたときに
こういうのを自動でするための機能です
これくらいのシンプルな関数だと中身を変更しない限り結果変わらないですし変更したらその場で確認をしてしまいますし自動でやる必要もないかもです
ですが 複雑な関数で どこかひとつ変えたらあっちこっちが影響するってときに全部を手動で確認してまわるのは大変ですよね
確認するのにデータを準備しないといけないときもあったりしますし
まぁ大丈夫でしょ と確認しなかったときほどバグがあったりするものです
というわけで ある程度大きなものでバグがないことをちゃんと確認しないといけないものを作るときにはテストツールは役立ちます
このツールでのテストは VisualStudio にもともとついてる機能なのでとっても簡単にできます
ほかにも .NET 用の NUnit というのもあるようですが こっちは外部ツールなので VisualStudio の拡張機能が必要そうです
VisualStudio 自体を拡張する機能は Express では使えなくて Community 以上でないといけないです
そういうこともあって こだわらないなら何もしないで使える MSTest でいいと思います
テストというと
などなど色々種類が出てきますが MSTest は単体テスト (Unit test) ツールに当たるようです
単体テストというと最小の単位でひとつひとつの機能がちゃんと動いてるか確認するものです
単体テストツールというと基本は Assert があるだけです
Assert の引数に true になるべき値を渡します
もし false なら例外が起きます
例外が起きたかどうかをまとめてレポートしてくれるのがツールの機能です
Assert は引数が true になるかだけのシンプルなものあれば 引数が 2 つで同じ値になっているか や コレクションと長さを渡してコレクションの長さが指定のものになっているかなど楽で見やすくなるようメソッドの種類がたくさんあるものもあります
もしなくても
のように true かどうかの判定だけでもできなくないですが やっぱり
注意ですが↑のコードはあくまで例なので MSTest の書き方ではないです
エディタ部分を適当に右クリックすれば 「単体テストの作成」 というのがあります
これを選ぶと自動でテストが作られます
右クリックしたのがメソッドの中だとそのメソッドだけが クラスの中のメソッド一覧のテストケースが作られます
こんなウィンドウが出てきます

プロジェクトの名前やテストのメソッド名や名前空間などの設定ができます
MSTest 以外のテストツールを拡張機能で入れているとそれに変更もできます
こだわりがないならデフォルトで おっけいです
ただ インナークラスのテストを自動生成などで名前空間が競合するような構造になることもあるのでそういうときはエラーにならないように修正します
自動で作られたテストファイルには
が書かれていて ここに Assert 系関数があります
自動で作られるのは public なメソッドだけです
private はリフレクション使えばテスト可能ですが 自動では作ってくれません
また class も public でないといけないです
デフォルトは internal なのでリフレクションしないとテスト用別アセンブリから参照できないからです
クラスは自動で作ることが多くて public 書いてないのが多いのでテスト作るときにまとめて public することになることが多そうです
Class1 を右クリックして単体テストの作成を選んで自動で作られたファイルの各メソッドの中をうめます
実行はテストケースファイルのエディタ上で右クリックして 「テストの実行」 をクリックします
breakpoint つけて途中の値をみたりデバッグしたいときは 「テストのデバッグ」 です
ここも クラスをクリックするかメソッドの中をクリックするかでクラス全体のテストを行うかメソッド単体のテストを行うかが変わります
実行するとデフォルトだと左側にテストエクスプローラがでてきます

成功したら緑色 失敗したら赤色になります
テストエクスプローラを手動で表示するときはメニューバーの 「テスト>ウィンドウ>テストエクスプローラ」 です
他のソリューションエクスプローラやエラー一覧などと同じようなサブウィンドウですがメニューの「表示」じゃなくて「テスト」にいるのでちょっと注意です
テストツールによっては setup/teardown だったりしますが MSTest では initialize/cleanup です
こんな感じです
ClassInitialize/ClassCleanup はクラス単位の最初と最後にする処理です
TestInitialize/TestCleanup はテスト(メソッド)単位の最初と最後にする処理です
どちらもメソッド名ではなく属性(メソッド定義の上の [] )で指定します
メソッドの中身ですが System.Diagonostics.Debug.WriteLine で出力できます
System.Console.WriteLine ではコンソールに表示されません
また デバッグモードで実行しないと Debug.WriteLine でもコンソールに出ないです
通常実行した場合で出力を見たいときは テストエクスプローラの各項目の「出力」から見れます
ただし 複数テストメソッドがあった場合に ClassInitialize/ClassCleanup が別れてしまうのとテストメソッドの実行順序がわからなくなるのとデストラクタは表示されないなどの問題があります
なので 例ではファイル出力にしてます
デバッグモードで実行すればいいのですが あいだあいだに余計なのがいっぱい入ってきて邪魔なんですよねー
ところで ClassInitialize/ClassCleanup は static メソッドです
static にしないとエラーになります
static だとインスタンスメソッドが呼べないとかプロパティを設定できないとか不便なところがあるのでそういうことはコンストラクタでやってしまうとよさそうです
private なメソッドは public から呼び出されて実行されるのが普通ですし public メソッドの動作が完璧なら中で使われてる private メソッドにも間違いはないはずです
なので基本的には public だけで十分だと思います
public から呼び出されてない あるのに実際は使われていない private メソッドがあってもそれをムダにチェックしなくて済みますしね
でも クラスに public メソッドがひとつだけで中に private メソッドがいっぱいある作りでメソッドごとにチェックした方がわかりやすいってときもあります
private メソッドは自動で生成されないだけで リフレクションを使えば外からも実行できます
なのでテストすることは可能です
こんな感じです
リフレクションなので長めですが 共通部分をまとめてしまえばもうちょっと短くできます
↓書いたらリンクが付きます
Assert
UIA
メニューにあれこれありすぎて使っていないのが多いですけど今回はこれを使ってみます
テストって
テストというと書いたコードがちゃんと動いてるかなーって確認するものです例えばこういうコード書いたときに
private bool isOdd(int val)
{
return val % 2 == 1;
}
isOdd(2) // false
isOdd(9) // true
isOdd(0) // false
という感じで適当に数値入れて思い通りの結果になってるか確認しますよねこういうのを自動でするための機能です
これくらいのシンプルな関数だと中身を変更しない限り結果変わらないですし変更したらその場で確認をしてしまいますし自動でやる必要もないかもです
ですが 複雑な関数で どこかひとつ変えたらあっちこっちが影響するってときに全部を手動で確認してまわるのは大変ですよね
確認するのにデータを準備しないといけないときもあったりしますし
まぁ大丈夫でしょ と確認しなかったときほどバグがあったりするものです
というわけで ある程度大きなものでバグがないことをちゃんと確認しないといけないものを作るときにはテストツールは役立ちます
テストツール
VisualStudio についてるテストツールは MS Test というもののようですこのツールでのテストは VisualStudio にもともとついてる機能なのでとっても簡単にできます
ほかにも .NET 用の NUnit というのもあるようですが こっちは外部ツールなので VisualStudio の拡張機能が必要そうです
VisualStudio 自体を拡張する機能は Express では使えなくて Community 以上でないといけないです
そういうこともあって こだわらないなら何もしないで使える MSTest でいいと思います
テストというと
- ブラックボックステスト
- ホワイトボックステスト
- 回帰テスト
- 単体テスト
- 結合テスト
- 負荷テスト
- E2Eテスト
などなど色々種類が出てきますが MSTest は単体テスト (Unit test) ツールに当たるようです
単体テストというと最小の単位でひとつひとつの機能がちゃんと動いてるか確認するものです
単体テストツールというと基本は Assert があるだけです
Assert の引数に true になるべき値を渡します
もし false なら例外が起きます
例外が起きたかどうかをまとめてレポートしてくれるのがツールの機能です
Assert は引数が true になるかだけのシンプルなものあれば 引数が 2 つで同じ値になっているか や コレクションと長さを渡してコレクションの長さが指定のものになっているかなど楽で見やすくなるようメソッドの種類がたくさんあるものもあります
もしなくても
Assert(x1 == x2);
Assert(items.Count == count);
のように true かどうかの判定だけでもできなくないですが やっぱり
AssertEqual(x1, x2);
AssertCountEqual(items, count);
こう書けたほうがいいですからね注意ですが↑のコードはあくまで例なので MSTest の書き方ではないです
MSTest
VisualStudio でテストを作るのは簡単エディタ部分を適当に右クリックすれば 「単体テストの作成」 というのがあります
これを選ぶと自動でテストが作られます
右クリックしたのがメソッドの中だとそのメソッドだけが クラスの中のメソッド一覧のテストケースが作られます
こんなウィンドウが出てきます

プロジェクトの名前やテストのメソッド名や名前空間などの設定ができます
MSTest 以外のテストツールを拡張機能で入れているとそれに変更もできます
こだわりがないならデフォルトで おっけいです
ただ インナークラスのテストを自動生成などで名前空間が競合するような構造になることもあるのでそういうときはエラーにならないように修正します
自動で作られたテストファイルには
using Microsoft.VisualStudio.TestTools.UnitTesting;
が書かれていて ここに Assert 系関数があります
自動で作られるのは public なメソッドだけです
private はリフレクション使えばテスト可能ですが 自動では作ってくれません
また class も public でないといけないです
デフォルトは internal なのでリフレクションしないとテスト用別アセンブリから参照できないからです
クラスは自動で作ることが多くて public 書いてないのが多いのでテスト作るときにまとめて public することになることが多そうです
サンプル
こんなクラスを作りますnamespace wpf_sample_proj
{
public class Class1
{
public int num { get; set; } = 0;
public Class1()
{
}
public Class1(int n)
{
this.num = n;
}
public void plus(int n)
{
this.num += n;
}
public void minus(int n)
{
this.num -= n;
}
public int get()
{
return this.num;
}
}
}
Class1 を右クリックして単体テストの作成を選んで自動で作られたファイルの各メソッドの中をうめます
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace wpf_sample_proj.Tests
{
[TestClass()]
public class Class1Tests
{
[TestMethod()]
public void Class1Test()
{
var inst = new Class1();
Assert.AreEqual(0, inst.num);
}
[TestMethod()]
public void Class1Test1()
{
var inst = new Class1(3);
Assert.AreEqual(3, inst.num);
}
[TestMethod()]
public void plusTest()
{
var inst = new Class1();
inst.plus(19);
Assert.AreEqual(19, inst.num);
}
[TestMethod()]
public void minusTest()
{
var inst = new Class1();
inst.minus(4);
Assert.AreEqual(-4, inst.num);
}
[TestMethod()]
public void getTest()
{
var inst = new Class1(55);
Assert.AreEqual(inst.num, inst.get());
}
}
}
実行はテストケースファイルのエディタ上で右クリックして 「テストの実行」 をクリックします
breakpoint つけて途中の値をみたりデバッグしたいときは 「テストのデバッグ」 です
ここも クラスをクリックするかメソッドの中をクリックするかでクラス全体のテストを行うかメソッド単体のテストを行うかが変わります
実行するとデフォルトだと左側にテストエクスプローラがでてきます

成功したら緑色 失敗したら赤色になります
テストエクスプローラを手動で表示するときはメニューバーの 「テスト>ウィンドウ>テストエクスプローラ」 です
他のソリューションエクスプローラやエラー一覧などと同じようなサブウィンドウですがメニューの「表示」じゃなくて「テスト」にいるのでちょっと注意です
テスト前や後になにかしたい
それぞれのテスト前に初期化したり テスト後に終了処理したり ということもできますテストツールによっては setup/teardown だったりしますが MSTest では initialize/cleanup です
こんな感じです
namespace Tests
{
[TestClass()]
public class SampleClass
{
public SampleClass()
{
Debug.WriteLine("test-constructor");
new FileWriter().write("test-constructor");
}
~SampleClass()
{
Debug.WriteLine("test-destructor");
new FileWriter().write("test-destructor");
}
[ClassInitialize()]
public static void classInitialize(TestContext test_context)
{
Debug.WriteLine("class-initialize");
new FileWriter().write("class-initialize");
}
[ClassCleanup()]
public static void classCleanup()
{
Debug.WriteLine("class-cleanup");
new FileWriter().write("class-cleanup");
}
[TestInitialize()]
public void testInitialize()
{
Debug.WriteLine("test-initialize");
new FileWriter().write("test-initialize");
}
[TestCleanup()]
public void testCleanup()
{
Debug.WriteLine("test-cleanup");
new FileWriter().write("test-cleanup");
}
[TestMethod()]
public void testMethod()
{
Debug.WriteLine("test");
new FileWriter().write("test");
Assert.IsTrue(true);
}
}
}
12:51:08.537: test-constructor
12:51:08.541: class-initialize
12:51:08.545: test-initialize
12:51:08.549: test
12:51:08.554: test-cleanup
12:51:08.563: class-cleanup
12:51:08.568: test-destructor
ClassInitialize/ClassCleanup はクラス単位の最初と最後にする処理です
TestInitialize/TestCleanup はテスト(メソッド)単位の最初と最後にする処理です
どちらもメソッド名ではなく属性(メソッド定義の上の [] )で指定します
メソッドの中身ですが System.Diagonostics.Debug.WriteLine で出力できます
System.Console.WriteLine ではコンソールに表示されません
また デバッグモードで実行しないと Debug.WriteLine でもコンソールに出ないです
通常実行した場合で出力を見たいときは テストエクスプローラの各項目の「出力」から見れます
ただし 複数テストメソッドがあった場合に ClassInitialize/ClassCleanup が別れてしまうのとテストメソッドの実行順序がわからなくなるのとデストラクタは表示されないなどの問題があります
なので 例ではファイル出力にしてます
デバッグモードで実行すればいいのですが あいだあいだに余計なのがいっぱい入ってきて邪魔なんですよねー
ところで ClassInitialize/ClassCleanup は static メソッドです
static にしないとエラーになります
static だとインスタンスメソッドが呼べないとかプロパティを設定できないとか不便なところがあるのでそういうことはコンストラクタでやってしまうとよさそうです
private のテスト
上の方にも書きましたが自動生成では public なものしか作れませんprivate なメソッドは public から呼び出されて実行されるのが普通ですし public メソッドの動作が完璧なら中で使われてる private メソッドにも間違いはないはずです
なので基本的には public だけで十分だと思います
public から呼び出されてない あるのに実際は使われていない private メソッドがあってもそれをムダにチェックしなくて済みますしね
でも クラスに public メソッドがひとつだけで中に private メソッドがいっぱいある作りでメソッドごとにチェックした方がわかりやすいってときもあります
private メソッドは自動で生成されないだけで リフレクションを使えば外からも実行できます
なのでテストすることは可能です
こんな感じです
[TestMethod()]
public void privateTest()
{
var type = Type.GetType("project1.Class1, project1");
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("privateMethod", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var result = method.Invoke(instance, new object[] { 1 });
Assert.AreEqual(1, result);
}
リフレクションなので長めですが 共通部分をまとめてしまえばもうちょっと短くできます
続く
Assert の種類や UIA も書きたかったのですが長くなってきたので別記事にします↓書いたらリンクが付きます
Assert
UIA