ソフトウェア開発には、その考え方や特徴によって「○○開発」と名前が付いている開発プロセスがいくつかありますが、今回はビヘイビア駆動開発(BDD)というものに触れる機会があったので、その覚え書きです。
目次
ビヘイビア駆動開発とは?
ビヘイビア駆動開発(以下、BDD)とは、ソフトウェアの「振る舞い」に注目した手法です。あらかじめ、開発したいソフトウェアの仕様を「振る舞い」として定義しておき、それを満たすコードを実装するというやり方を取ります。
事前にテストコードを作成する形になるので、テストファーストの開発手法の1つです。
SpecflowでBDDに触れてみる
一般的なテスト駆動開発と違い、BDDは自然言語に近い構文でテストを記述していくことが特徴的です。これを実現するためのフレームワークとして、今回はSpecflowというツールを使ってみます。
SpecflowはCucumberというBDDフレームワークのC#版で、VisualStudioに組み込んで使うことができます。ということで、さっそくBDDの一端に触れてみましょう(・∀・)
Specflowプラグインの導入
まずは、VisualStudioにSpecflowのプラグインを導入します。VS2010以降(Express版以外)に対応しているので、今回はVS2017(Community版)に導入してみました。導入自体は「ツール」>「拡張機能と更新プログラム」から検索してインストールするだけです。
テストプロジェクトの作成
続いて、テストプロジェクトを作成します。「ファイル」>「新規作成」>「プロジェクト」からC#の単体テストプロジェクトを選択します。
プロジェクトができたら、デフォルトで作成されるテストコード(UnitTest1.cs)は不要なので削除しておきます。
必要なファイルのインストール
Specflowの動作に必要なファイルをインストールしていきます。「ツール」>「NuGetパッケージマネージャー」>「パッケージマネージャーコンソール」を開いて、以下のコマンドを実行します。
プロジェクト中に「App.config」という設定ファイルができていれば、インストールは成功です。
Featureファイルの作成
ここからはテストシナリオの作成に入ります。まずはFeatureファイルというファイルを作ります。プロジェクトで「追加」>「新しい項目」>「Specflow Feature File」を選択します。
すると、以下のように英語で書かれたファイルが追加されますが、実はこれがテストシナリオそのものです。このように自然言語でテストシナリオを記述できるのが、BDDの特徴となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Feature: SpecFlowFeature1 In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers @mytag Scenario: Add two numbers Given I have entered 50 into the calculator And I have also entered 70 into the calculator When I press add Then the result should be 120 on the screen |
上記のテストシナリオでは、電卓の足し算を例にいくつかのキーワードでシナリオを定義しています。以下、各キーワードとそれに対応したシナリオの説明です。
キーワード | 意味 | シナリオ |
Given | 事前条件 | 電卓に50を入力する |
And | 追加の事前条件 | 電卓に70を入力する |
When | 試行 | 足し算のボタンを押す |
Then | 事後条件(期待する結果) | 結果が120となっていること |
一見するとテストコードに見えませんが、これをSpecflowが解釈してテストとして実行してくれます。これにはちょっとびっくりしました(゚_゚;)
Stepファイルの作成
もちろん、シナリオだけではテストができないので、シナリオと紐付けるテストコードを実装する必要があります。
まずは、テストそのものを実行するテストランナーを指定します。App.configを開き、以下のような記述を書き加えます。今回はVS2017にデフォルトで入っているMSTestを指定しました。
続いて、先ほど作成したFeatureファイルを開き「右クリック」>「Generate Step Definitions」を選択すると、以下のようなウインドウが開きます。シナリオ全てが選択されていることを確認し「Generate」を押下しましょう。
これでfeatureファイルに定義したシナリオに対応したテストコードのひな形が自動生成されます。ちゃんと各キーワードに対応したメソッドが用意されていることが分かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System; using TechTalk.SpecFlow; namespace CalcTest { [Binding] public class SpecFlowFeature1Steps { [Given(@"I have entered (.*) into the calculator")] public void GivenIHaveEnteredIntoTheCalculator(int p0) { ScenarioContext.Current.Pending(); } [Given(@"I have also entered (.*) into the calculator")] public void GivenIHaveAlsoEnteredIntoTheCalculator(int p0) { ScenarioContext.Current.Pending(); } [When(@"I press add")] public void WhenIPressAdd() { ScenarioContext.Current.Pending(); } [Then(@"the result should be (.*) on the screen")] public void ThenTheResultShouldBeOnTheScreen(int p0) { ScenarioContext.Current.Pending(); } } } |
テスト対象の作成とテストコード実装
ここまでで、テストシナリオ+テストコードのひな形は作成できました。あとはテスト対象となるプログラムと、それに合わせたテストコードを実装していくだけです。
まずは電卓クラス。今回は簡単のために、2つの数の足し算のみを実装しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
namespace Calc { public class Calculator { public int number1; public int number2; public int Add() { return number1 + number2; } } } |
続いてテストコード。こちらは電卓クラスのインスタンスを最初に作成し、各シナリオに対応するメソッド中でそのインスタンスに対する操作をしています。最後の「Then」に対応するコードは計算結果のチェックなので、Assertを入れています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using TechTalk.SpecFlow; using Calc; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CalcTest { [Binding] public class SpecFlowFeature1Steps { private Calculator calc = new Calculator(); private int result; [Given(@"I have entered (.*) into the calculator")] public void GivenIHaveEnteredIntoTheCalculator(int n) { calc.number1 = n; } [Given(@"I have also entered (.*) into the calculator")] public void GivenIHaveAlsoEnteredIntoTheCalculator(int n) { calc.number2 = n; } [When(@"I press add")] public void WhenIPressAdd() { result = calc.Add(); } [Then(@"the result should be (.*) on the screen")] public void ThenTheResultShouldBeOnTheScreen(int expected) { Assert.AreEqual(expected, result); } } } |
テスト実行
ようやくテスト実行までこぎ着けました。「テストエクスプローラー」>「すべて実行」からテストを実行してみます。ちゃんと足し算ができているようですね(・∀・)
このように、自然言語に近い形で記述したテストシナリオに従ってテストを実行することができました。
まとめ
今回はだいぶ簡単な例ではありましたが、Specflowを使ってBDDの一端に触れてみました。
個人的に感じたところとしては、テストシナリオ自体を自然言語で書けるところはかなり魅力的でした。あとから振り返っても何をテストしたいのか一目瞭然なので、メンテナンス性も上がりそうです。
なかなかテスト手法に対して学ぶ機会は多くないので、今回はとても良い勉強になりました。興味のある方はこれを参考に試してみてはいかがでしょうか?
ではではノシ