Scalaでテストを実行してみる。TDD(Test-Driven Development)って何ぞ~?

f:id:ts0818:20191026160317p:plain

'Do you know the Borsalino hat test?'

Shantaram (novel) - Wikipedia

⇧  テストと言えば、そう、「Borsalino hat test」ですね!どうも、ボクです。


Shantaram

⇧  原書も評価が高いですが、私は、英語が苦手なので、


シャンタラム(上) (新潮文庫)


シャンタラム(中) (新潮文庫)


シャンタラム(下) (新潮文庫)

⇧  日本語版で読みましたけど。解説が養老孟司さんだったので、読んだんですが、面白かったです。

「シャンタラム(著:グレゴリー・デイヴィッド・ロバーツ)」という小説の中で、「ボルサリーノ・テスト」って出てきます。 

 『帽子を円柱状に、細長い円筒の形にして、結婚指輪に通した後で、帽子が元の状態に戻ったら、本物のボルサリーノ』というのが「ボルサリーノ・テスト」らしい。

 

ボルサリーノは、

ボルサリーノイタリア語Borsalino)は、イタリアアレッサンドリアに本社を置く帽子メーカー及びブランドである。

ボルサリーノ - Wikipedia

⇧  イタリアの帽子メーカー、ブランドであると。

そのものズバリな、

ボルサリーノ』(原題: Borsalino )は、1970年公開のフランスイタリア合作映画。出演は当時フランスで大スターであり、日本でも人気の高かったジャン=ポール・ベルモンドアラン・ドロン。続編として1974年に公開されたボルサリーノ2英語版がある。

ボルサリーノ (映画) - Wikipedia

⇧  「ボルサリーノ」って映画まで出てる。 

そんな、「ボルサリーノ」も、

2017年12月18日に破産手続きを行ったと報道された。2016年以来ブランドの活動を管理してきたHaeres Equita社は、将来のコレクションの生産、流通および販売を継続し、すべての雇用を維持し、アレッサンドリア(ピエモント)の生産拠点を維持すると確約した

ボルサリーノ - Wikipedia

⇧  不況には勝てないけど...

ただ、

style.nikkei.com

――160年の歴史があり、顧客には著名人が多いです。

「政治家にビジネス界、映画界と、ラッキーなことに4世代にわたってファンがいます。米国ならハンフリー・ボガートロバート・レッドフォードジョニー・デップファレル・ウィリアムスといった具合にです。欧州ではアラン・ドロン、日本では麻生太郎ら各氏がイメージアップに貢献してくれています」

麻生氏も愛用 伊高級帽子「ボルサリーノ」が日本攻勢|Men's Fashion|NIKKEI STYLE

⇧  著名人の顧客は多いらしいと。金持ちは違いますな~。 

まぁ、そんなこんなで、脱線しまくりましたが、今回は、Scalaでテスト実行までしていきたいですかね。レッツトライ~。

 

TDD(Test-Driven Development)って何?

Wikipediaさ~ん!

テスト駆動開発 (てすとくどうかいはつ、test-driven development; TDD) とは、プログラム開発手法の一種で、プログラムに必要な各機能について、最初にテストを書き(これをテストファーストと言う)、そのテストが動作する必要最低限な実装をとりあえず行った後、コードを洗練させる、という短い工程を繰り返すスタイルである。多くのアジャイルソフトウェア開発手法、例えばエクストリーム・プログラミングにおいて強く推奨されている。近年はビヘイビア駆動開発へと発展を遂げている。

テスト駆動開発 - Wikipedia

⇧  設計において各機能の仕様が定まったら、通常なら製造に進むところを、テストコードを書く ということらしい。

最も基本となる開発サイクルは以下のようになる。

  • 失敗するテストを書く
  • できる限り早く、テストに通るような最小限のコードを書く
  • コードの重複を除去する(リファクタリング

なお、テストの実行環境ツールであるxUnitでは、テストの失敗を赤いバー、成功を緑のバーで通知するため、上記のサイクルは Red/Green/Refactor と称される。

テスト駆動開発 - Wikipedia

⇧  『テスト駆動開発』と呼ばれる所以は、「Red → Green → Refactor」とあるように、テストをキッカケ(駆動)に、開発を進めていくということだからかと。

じゃあ、これの何が嬉しいのか?

システム開発のゴールは、あくまで、動くシステムが出来上がり、システムを求めていた顧客に利用してもらうことであるはずであると。

つまり、最終的には、動くプログラミングのソースコードが必要なんだと。

システム開発の際、通常の「ウォーターフォール」モデルの開発では、

設計工程 設計工程に対応する製造・テスト工程
要求定義 受入テスト
要件定義 統合テスト、業務結合テスト
外部設計、方式設計 システム結合テスト
内部設計、詳細設計 製造・単体テスト(UT:Unit Test、ユニットテスト)

みたいな、流れが一般的かと。(用語は、プロジェクトによってまちまちですかね。)

なので、流れ的には、

要求定義 → 要件定義 → 外部設計、方式設計 → 内部設計、詳細設計 → 製造・単体テスト → システム結合テスト → 統合テスト、業務結合テスト → 受入テスト → お客様が利用

っていうフェーズで開発は進んでいくんだと。

 

thinkit.co.jp

エンドユーザーの満足を目的として考えられている反復型のプロセスモデルとしてスクラムが挙げられます。ウォーターフォール型では、要求定義から実装までを一度だけ行う前提でプロセスが考えられています。一方、スクラムをはじめとする反復型では、要求定義から実装までを繰り返し行う前提でプロセスが考えられています。

いろいろなプロセス ~V字モデルとスクラム~ | Think IT(シンクイット)

⇧  上記サイト様にありますように、最近は、「スクラム」モデルの開発がイケてるらしいっす。

スクラムScrum)は、ソフトウェア開発における反復的で漸進的なアジャイルソフトウェア開発手法の1つである。この方法論は「柔軟かつ全人的なプロダクト開発ストラテジーであり、共通のゴールに到達するため、開発チームが一体となって働くこと」とされる。

スクラム (ソフトウェア開発) - Wikipedia

この方法論は、製品開発における伝統的な、シーケンシャルなアプローチとは大きく異なる。この方法論は、チームが自発的に組織だって行動することを可能にする。

この自己組織化を実現するのは、すべてのチームメンバーが物理的に同じ場所にいること、あるいは密なオンライン共同作業を通じ、全員が日々直接会ってお互いにコミュニケーションをとり、プロジェクトにおける規律を守ることである。

スクラム (ソフトウェア開発) - Wikipedia

スクラムのカギとなる基本原則は、プロジェクト開発の途中で、顧客は、要求や必要事項を変えられるという認識である。予想できない変更について、計画に基づく方法で対処することは、容易ではない。したがって、スクラムは経験に基づくアプローチを採用する。問題を十分に理解することも、定義することもできないので、現れた要求へ素早く対応するためのチームの能力を最大化することに集中する、というアプローチである。

スクラム (ソフトウェア開発) - Wikipedia

⇧  何か、すごい揉めそうな気がするけど... 言った、言わない論争とかね...

ちなみに、

qiita.com

⇧  上記サイト様によりますと、アジャイルスクラムですと。

アジャイル」が「仕様」で、「スクラム」が「実装」ってことですかね?

 

脱線しましたが、通常、開発と言えば、 設計書通りに製造(ソースコードを記述する)することになるのですが、『その設計書で問題はないのかしら?』って確認するにはどうするか?

確認には、レビュー(設計書の妥当性を精査する)とかを行うわけですが、設計書をレビューすると言っても、人間がすることですからどうしたって漏れが出てくると、と言うか、設計書を見ててもよく分からんモヤモヤした部分は当然出てくると。

そんじゃぁ、どうするか?

設計書に書いた機能を実装して確認してしまえば良くない?

つまり、動けば正義、動くプログラミングこそ全て!って言いきることはできないですが(保守とかも考えると、改修しにくいコーディングはNGですかね)、少なくとも、動くソースコードが無ければ改善の仕様が無いのだと。

ソースコードで言えば、メソッドが機能にあたると思われるので、メソッドのテストを先にやってしまえ~、って方向になるかと。

 

ただし、 

dev.classmethod.jp

qiita.com

⇧  「TDD(Test-Driven Development)」も「銀の弾丸」 ではないと。

銀の弾丸(ぎんのだんがん、silver bullet)とは、で作られた弾丸で、西洋の信仰において狼男悪魔などを撃退できるとされ、装飾を施された護身用拳銃と共に製作される。

銀の弾丸 - Wikipedia

転じて、尋常な手段だけでは厄介な対象を一撃で葬るもの、という比喩表現として用いられる場合が多い。例えば、ある事象に対する対処の決め手や特効薬、あるいはスポーツで相手チームのエース選手を封じ込める選手などを表現する場合に用いられる。

また、ソフトウェア工学では、OS/360の開発で苦闘したフレデリック・ブルックスが、『人月の神話』(1975年(原書))において「『どんな場合であれ通用する』ような、『万能な解決策』は存在しない」というたとえとして「銀の弾などない」と述べた例がよく引き合いに出され、しばしばある種の企業の広告などに見られるそのような主張に対して言われる言葉になっている。

銀の弾丸 - Wikipedia

⇧  確かに、「銀の弾丸など存在しない」って言葉は、IT業界で良く聞きますね。

 

話を戻して、「TDD」が有効と思われるのは、画面側ではなく、変更が発生しにくい業務ロジック部分の実装に向いていそうだと。まさに、サーバ側のビジネスロジック部分なんかには蓋し、もってこいになるのかと。

だ~け~ど、あくまで、「銀の弾丸」ではないので、すべてに効果があるとは思えないですが、「単体テスト」においての効果は高いのではないかと。

「システム結合テスト」などの、各機能を組み合わせた結果を検証するテストにおいては「TDD」適応が難しいかと、まぁ、このへんのテストになってくると、それぞれの機能はほぼ完成してる体のはずだしね。 

 

Scala単体テスト(UT:Unit Test、ユニットテスト)してみる

とりあえず、Scala単体テストしてみますか。

 Javaだと、単体テスト用のAPIとして「JUnit」が一般的かと思われますが、Scalaだと、「ScalaTest」というものが一般的になるのかと。


seratch.hatenablog.jp

dev.classmethod.jp

 

ScalaTestの本家サイトによりますと、

www.scalatest.org

ScalaTest is the most flexible and most popular testing tool in the Scala ecosystem. With ScalaTest, you can test Scala, Scala.js (JavaScript), and Java code. By offering deep integration with tools such as JUnit, TestNG, Ant, Maven, sbt, ScalaCheck, JMock, EasyMock, Mockito, ScalaMock, Selenium, Eclipse, NetBeans, and IntelliJ, ScalaTest makes it easy to take your testing to a higher, more productive level in new or existing Scala, Scala.js, or Java projects.

ScalaTest

⇧  Scala だけじゃなくて、Javaソースコードもテストしてくれるらしい。

とりあえず、sbtでScalaを利用する場合は、標準で導入されてるAPIではないらしく、

docs.scala-lang.org

⇧  「build.sbt」の「libraryDependencies」 プロパティに「ScalaTest」を追加し、依存関係を解決してあげないといけないようです。

 

今回は、

ts0818.hatenablog.com

⇧  この記事で導入した、Scalaプロジェクトを利用していきたいと思います。 

そんでは、Visual Studio Code を起動で。そしたら、Scalaプロジェクト内の「build.sbt」ファイルを編集していきます。

f:id:ts0818:20191026175220p:plain

こんな感じになってるので、 

version := "1.2.8"
libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.12.7"

「ScalaTest」のAPIを利用できるように、依存関係を追記で。

version := "1.2.8"
libraryDependencies ++= Seq(
  "org.scala-lang" % "scala-reflect" % "2.12.7",
  "org.scalatest" %% "scalatest" % "3.0.8" % "test"
)   

んで、ファイルを保存すると、Visual Studio Code にインストールしていた拡張機能「Metals」が更新を促してくるので、「Import changes」で。

f:id:ts0818:20191026180245p:plain

で、リフレクションを導入した時みたいに、「C:\Program Files (x86)\sbt\lib\local-preloaded」に、「org.scalatest」パッケージがインストールされて...

f:id:ts0818:20191026203400p:plain

ないやんけ~!

検索かけてみたとところ、

f:id:ts0818:20191026192945p:plain

⇧  キャッシュとして保存はされてるらしい...

  • C:\Users\Toshinobu\.ivy2\cache\org.scalatest\scalatest_2.12
    • \bundles\scalatest_2.12-3.0.8.jar
    • \srcs\scalatest_2.12-3.0.8-sources.jar
  • C:\Users\Toshinobu\.IdeaIC2019.2\config\plugins\Scala\lib
    • scalatest-finders-patched-0.9.9.jar

んで、Visual Studio Code の「表示」>「出力」に表示されたログを抜粋。 

...省略

[info] Updating ...
[info] downloading https://repo1.maven.org/maven2/org/scalactic/scalactic_2.12/3.0.8/scalactic_2.12-3.0.8.jar ...
[info] downloading https://repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.2.0/scala-xml_2.12-1.2.0.jar ...
[info] downloading https://repo1.maven.org/maven2/org/scalatest/scalatest_2.12/3.0.8/scalatest_2.12-3.0.8.jar ...
[info] 	[SUCCESSFUL ] org.scala-lang.modules#scala-xml_2.12;1.2.0!scala-xml_2.12.jar(bundle) (1499ms)
[info] 	[SUCCESSFUL ] org.scalactic#scalactic_2.12;3.0.8!scalactic_2.12.jar(bundle) (2034ms)
[info] 	[SUCCESSFUL ] org.scalatest#scalatest_2.12;3.0.8!scalatest_2.12.jar(bundle) (3786ms)
[info] Done updating.
[info] downloading https://repo1.maven.org/maven2/org/scalactic/scalactic_2.12/3.0.8/scalactic_2.12-3.0.8-sources.jar ...
[info] downloading https://repo1.maven.org/maven2/org/scalatest/scalatest_2.12/3.0.8/scalatest_2.12-3.0.8-sources.jar ...
[info] downloading https://repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.2.0/scala-xml_2.12-1.2.0-sources.jar ...
[info] 	[SUCCESSFUL ] org.scalactic#scalactic_2.12;3.0.8!scalactic_2.12.jar(src) (764ms)
[info] 	[SUCCESSFUL ] org.scala-lang.modules#scala-xml_2.12;1.2.0!scala-xml_2.12.jar(src) (799ms)
[info] 	[SUCCESSFUL ] org.scalatest#scalatest_2.12;3.0.8!scalatest_2.12.jar(src) (1236ms)
[success] Generated .bloop\testreflection.json
[success] Generated .bloop\testreflection-test.json
[success] Total time: 10 s, completed 2019/10/26 18:04:17
build tool exit: 0
time: ran 'sbt bloopInstall' in 38s
disconnected: build server
bloop exit: 0
running embedded 'bloop bsp --protocol tcp --host 127.0.0.1 --port 51476'
tracing is disabled for protocol BSP, to enable tracing of incoming and outgoing JSON messages create an empty file at C:\Users\Toshinobu\AppData\Local\scalameta\metals\cache\bsp.trace.json
time: connected to build server in 6.44s
time: imported build in 0.26s
unknown command: metals-doctor-reload
time: indexed workspace in 1.47s
no build target: C:\Users\Toshinobu\Desktop\Scala\TestReflection\build.sbt

そう、なんか分からんけど、気になったんで、

『tracing is disabled for protocol BSP, to enable tracing of incoming and outgoing JSON messages create an empty file at C:\Users\Toshinobu\AppData\Local\scalameta\metals\cache\bsp.trace.json

の部分で、ググってみたところ、

github.com

Getting these in the OUTPUT logs
Empty build targets. Expected at least one build target identifier
tracing is disabled for protocol BSP, to enable tracing of incoming and outgoing JSON messages to create an empty file at /Users/../Library/Caches/org.scalameta.metals/bsp.trace.json

Can't get go to definitions to work in VS-Code · Issue #768 · scalameta/metals · GitHub

⇧  同じようなログが出てると。 

んで、それに対する回答が、

jvican commented on 15 Jun

This error is caused by bloop whenever a dependency of a project is found to be the project itself. You can see that in the definition of root in your build.sbt you apply dependsOn(... root), which is causing that problem.

However, it looks like the project ref in dependsOn is pointing to another project. Is that correct? I imagine that removing it makes your build fail, doesn't it?

Looks like this might be an error in how we resolve that dependency inside sbt. In the meanwhile, I'd recommend trying to modify your build not to use that project ref pointing to an http repository. That is quite a niche feature and it's not trivial to support.

Can't get go to definitions to work in VS-Code · Issue #768 · scalameta/metals · GitHub

olafurpg commented on 17 Jun

Thank you for reporting! The fix is to refactor build.sbt to avoid cyclic dependencies as explained by @jvican in #768 (comment). There isn't much we can do about this on the Metals side I'm afraid.

Can't get go to definitions to work in VS-Code · Issue #768 · scalameta/metals · GitHub

⇧  ってなっていて、「循環依存関係」が起こっているらしいと。

ホワッツ?

www.scala-sbt.org

セッティングが := や += や ++= を使って自分自身や他のキーへの依存が生まれるとき、その依存されるキーの値が存在しなくてならない。 もしそれが存在しなければ sbt に怒られることになるだろう。例えば、“Reference to undefined setting“ のようなエラーだ。 これが起こった場合は、キーが定義されている正しいスコープで使っているか確認しよう。

これはエラーになるが、循環した依存性を作ってしまうことも起こりうる。sbt が君がそうしてしまったことを教えてくれるだろう。

sbt Reference Manual — Combined Pages

⇧  う~ん...、 自分の場合は、なんか、[FATAL]、[ERROR]とかいうエラーは起こってないから「循環依存関係」じゃないんすかね。

 

ちょっと、Scalaの仕組みがよく分からんのだけれども、「ScalaTest」のAPI自体は読み込めているようです...謎すぎる。ログが紛らわしいな~。

f:id:ts0818:20191026202932p:plain

とりあえず、

f:id:ts0818:20191026204149p:plain

のように「CubeCalculator.scala」「CubeCalculatorTest.scala」ファイルを追加で。ディレクトリ構成にはご注意を。

んで、ソースコードを編集で。

object CubeCalculator extends App {
    def cube(x: Double): Double = {
        Math.pow(x, x)
    }
}    

 

import org.scalatest.FunSuite

class CubeCalculatorTest extends FunSuite {
    test("CubeCalculator.cube") {
        assert(CubeCalculator.cube(3) === 27.0)
    }
}    

Visual Studio Code の「ターミナル」でテストできるようなので、

docs.scala-lang.org

そのディレクトリに cd して、sbt test を実行します。 これは CubeCalculator.cube という1つのテストを含むテストスイート CubeCalculatorTest を実行します。

コマンドラインで ScalaTest を使って Scala をテストする | Scala Documentation

テスト実行ということで、ターミナルから実行。

sbt test

f:id:ts0818:20191026205452p:plain

f:id:ts0818:20191026205225p:plain

なんとか、テストの実施ができました~。

ちなみに、

qiita.com

⇧  Scala は、return を省略できるんだそうです。メソッド内で、return してなくても戻り値をちゃんと返せてますね。

それと、

www.oreilly.com

⇧  「build.sbt」の代わりに、「Build.scala」ってファイルも使えるんだそうな。

stackoverflow.com

⇧  「build.sbt」と「Build.scala」の違いは、よく分からんけど、なんか、「Build.scala」は非推奨とかになる?のかな。

github.com

⇧ という意見もあり。

Git Hubの「sbt 0.13.12」のバージョンのリリース情報には、

github.com

The Build trait is deprecated in favor of the .sbt format #2530 by @dwijnand

Release 0.13.12 · sbt/sbt · GitHub

⇧ と書いてはあるけど、これが、「Build.scala」が非推奨ってことを言っていることになるのかな? よく分からん。

 

そして、相変わらず、Metals(Scala language server with rich IDE features)を 使ってのテストができていませんが(涙)。

そして、TDD(Test-Drive Development)もできてないけど(哀)

今回もモヤモヤ感が半端ないですが。

今回はこのへんで。