言語のテストが構文レベルでサポートされている機能ではないのはなぜですか?


37

ソースコードの単体テストの利点を宣伝するブログ、記事、ウェブサイトの無限のリストを見つけることができます。Java、C ++、C#、およびその他の型付き言語用のコンパイラをプログラムした開発者は、ユニットテストを使用して作業を検証したことがほぼ保証されています。

それでは、なぜその人気にもかかわらず、これらの言語の構文にテストがないのでしょうか?

マイクロソフトはC#LINQを導入しましたが、なぜテストも追加できないのですか?

私は、これらの言語の変更がどうなるかを予測するつもりはありませんが、そもそもなぜそれらが変更されないのかを明確にするつもりです。

例として:ステートメントのfor構文なしでループを書くことができることを知っていますforwhileまたはif/ gotoステートメントを使用できます。誰かがfor声明がより効率的であると判断し、それを言語に導入しました。

テストがプログラミング言語の同じ進化に従っていないのはなぜですか?


24
一般的な方法で簡単に拡張できる単純なルールを使用して言語を設計するのではなく、構文を追加して言語仕様をより複雑にする方が本当に良いですか?
KChaloux 14

6
「構文レベルで」とはどういう意味ですか?実装方法に関する詳細/アイデアはありますか?
SJuan76 14

21
構文サポート機能としてのテストの擬似コード例を教えてください。私はあなたがそれがどのように見えると思うか見てみたいです。
FrustratedWithFormsDesigner

12
@FrustratedWithFormsDesigner例についてはD言語参照してください
ドーバル14

4
組み込みの単体テスト機能を備えた別の言語はRustです。
セバスチャンレッド14

回答:


36

多くの場合と同様に、ユニットテストは言語レベルではなくライブラリレベルで最適にサポートされます。特に、C#には多数の単体テストライブラリが用意されているほか、.NET FrameworkのネイティブなものもありますMicrosoft.VisualStudio.TestTools.UnitTesting

各単体テストライブラリには、テストの哲学と構文が多少異なります。すべてのものが平等であり、選択肢が多ければ少ないほど良い。単体テストが言語に組み込まれている場合、言語設計者の選択に縛られるか、ライブラリを使用して、言語テスト機能を完全に使用しないようにします。

  • Nunit -C#の言語機能を最大限に活用する、汎用的で慣用的に設計された単体テストフレームワーク。

  • Moq-記録/再生のメタファーなしで、ラムダ式と式ツリーを最大限に活用するモックフレームワーク。

他にも多くの選択肢があります。Microsoft Fakesのようなライブラリは、インターフェイスや仮想メソッドを使用してクラスを記述する必要のない「シム...」モックを作成できます。

Linqは言語機能ではありません(名前にもかかわらず)

Linqはライブラリ機能です。ラムダ式や拡張メソッドなど、C#言語自体に無料で多くの新機能が追加されましたが、Linqの実際の実装は.NET Frameworkにあります。

linqステートメントをよりクリーンにするためにC#に追加された構文糖がいくつかありますが、その糖はlinqを使用するために必須ではありません。


1
LINQは言語機能ではないが、LINQを実現するには、いくつかの基礎となる言語機能、特にジェネリック型とダイナミック型が必要であるという点には同意します。
ワイアットバーネット14

@WyattBarnett:はい。反射や属性など、簡単な単体テストにも同じことが言えます。
Doc Brown 14

8
LINQにはラムダと式ツリーが必要でした。ジェネリックは既にC#(および.Net全般、CLRに存在)にあり、ダイナミクスはLINQとは関係ありません。ダイナミックなしでLINQを実行できます。
アーサー・ヴァン・レーウェン14

PerlのDBIx :: Classは、それを実装するために必要なすべての機能が言語に組み込まれてから10年以上経って実装されたLINQのような機能の例です。
スリーブマン

2
@ Carson63000あなたはvarキーワードと組み合わせて匿名型を意味すると思います:)
M.Mimpen 14

21

理由はたくさんあります。Eric Lippertは、理由feature XはC#にないのは、予算にないからだと何度も述べています。言語設計者には、物事を実装するための無限の時間もお金もありません。また、各新機能には、それに関連するメンテナンスコストがあります。言語をできる限り小さく保つことは、言語設計者にとってだけでなく、代替の実装やツール(IDEなど)を作成する人にとっても簡単です。無料で移植可能。単体テストがライブラリとして実装されている場合、一度だけ記述するだけでよく、言語の準拠する実装で機能します。

Dには単体テストの構文レベルのサポートがあることに注意してください。彼らがなぜそれを投入することにしたのかはわかりませんが、Dが「高レベルのシステムプログラミング言語」であることを意図していることは注目に値します。設計者は、C ++が伝統的に使用されてきた、安全ではない低レベルのコードに対して実行可能であることを望んでいました。そのため、いくつかの安全でないコードが機能することを確認するのに役立つものに余分な労力を費やすことは、彼らにとって理にかなっていると思います。たとえば、特定の信頼できるモジュールのみが、未チェックの配列アクセスやポインター演算などの安全でない操作を実行できるように強制できます。

また、迅速な開発も優先事項であったため、Dコードをスクリプト言語として使用できるようにコンパイルするのに十分な速度でコンパイルするという設計目標を達成しました。ユニットテストを言語に直接ベイクして、追加のフラグをコンパイラに渡すだけでテストを実行できるようにします。

ただし、優れた単体テストライブラリは、いくつかのメソッドを見つけて実行するだけではありません。HaskellのQuickCheckを例にとると、f (x, y) == f (y, x)「すべてのxとyについて」などをテストできます。QuickCheckはユニットテストジェネレーターとして記述される方が適切であり、「この入力に対して、この出力を期待しています」よりも高いレベルでテストすることができます。QuickCheckとLinqの違いはそれほどありません。どちらもドメイン固有の言語です。ユニットテストのサポートを言語に追加するのではなく、DSLを実用的にするために必要な機能を追加してみませんか?ユニットテストだけでなく、結果としてより良い言語になります。


3
.Netの世界にとどまるために、F#にQuickCheckを移植したFsCheckがあり、C#から使用するためのヘルパーがいくつかあります。
アーサー・ヴァン・レーウェン14

.NETの世界にとどまるには?この質問は、.NETとは関係ありません。
マイルルーティング14

@MilesRout C#は.NETの一部です。質問と回答はC#について頻繁に語り、質問はLINQについても語っています。
ザカリーダウ

質問には.NETまたはC#のタグは付けられていません。
マイルルーティング

@MilesRoutそれは本当かもしれませんが、タグがないという理由だけでそれが何の関係もないと合理的に言うことはできません。:)
ザカリーダウ

13

テスト、特にテスト駆動開発は、直感に反する現象であるためです。

ほとんどすべてのプログラマーは、実際よりも複雑さの管理がはるかに優れていると信じてキャリアを開始します。偉大なプログラマーでさえ、多くの回帰テストを使用しない限り、重大なエラーなしに大きく複雑なプログラムを書くことができないという事実は、多くの実践者にとって非常に残念であり、恥ずべきことですらあります。したがって、すでによく知っているはずの専門家の間でも、定期的なテストに対する一般的な傾向。

宗教的なテストが徐々に主流になり、期待されているという事実は、ストレージ容量とコンピューティング能力の爆発的増加により、これまでよりも大きなシステムが構築されているという事実によるものだと思います-非常に大規模なシステムは、特に複雑さの崩壊に陥りやすい回帰テストのセーフティネットなしでは管理できません。その結果、特に頑固で妄想した開発者でさえ、テストが必要であり、常にテストが必要であることを不承不承に認めています(これがAAミーティングでの告白のように聞こえる場合、これは非常に意図的です-セーフティネットの必要性は多くの人々にとって心理的に難しい個人)。

今日人気のあるほとんどの言語は、この態度が変わる前のものであるため、テストのサポートはほとんど組み込まれてassertいません。傾向が続く場合、将来の言語はライブラリレベルではなく、その言語でより多くのサポートを受けると確信しています。


3
ケースを少し誇張します。単体テストは間違いなく最も重要ですが、プログラムを適切に構築することは、不必要な複雑さを最小限に抑える適切な方法であり、それ以上ではありません。Haskellのような言語には、書かれたプログラムの信頼性と証明可能性を向上させる型システムがあり、コーディングと設計のベストプラクティスにより、テストされていないコードの落とし穴の多くが回避され、単体テストの重要性が低くなります。
ロバートハーヴェイ14

1
@RobertHarve ...そして単体テストは、開発者を間接的にプッシュするための非常に良い方法です。他のコードでテストを使用するのではなく、テストの作成中にAPIで作業することで、漏れやすい抽象化や奇妙なメソッド呼び出しを制限または削除するために、正しい考え方にそれらを置くことができます。KillianFothが何も誇張しているとは思わない。
イズカタ14

@Robert:彼が誇張していると私が信じる唯一のことは、「宗教的なテストが徐々に主流になりつつある」ことです。地理的な時間枠でゆっくり定義されるなら、彼はおそらくそう遠くないでしょう..... :)
mattnz 14

+1現在の仕事では、利用可能な新しいライブラリとテクノロジーを使用した開発姿勢の大きな変化に驚いています。私のキャリアの中で初めて、これらの人が講義をしている私を、私は風に叫んで丘の上だような感じ私の代わりに、より洗練された開発プロセスを使用します。これらの態度が母国語の構文で表現を見つけるのは時間の問題だと思います。
ロブ

1
申し訳ありませんが、もう一度考えてみてください。ロバート・ハーベイのコメント。現在、型システムは良いチェックですが、型の制約を定義することには本当に驚くほど足りません-それらはインターフェースに対処しますが、正しい動作を制約しません。(つまり、1 + 1 == 3はコンパイルされますが、+の実装に応じて、真実である場合とそうでない場合があります)次の傾向は、現在単体テストと考えているものを組み合わせた、より表現力豊かな型システムを見るでしょうか?
ロブ14

6

多くの言語がテストをサポートしています。Cのアサートは、プログラムが失敗する可能性があるテストです。ここでほとんどの言語が停止しますが、エッフェルと最近のAda 2012には前不変式(関数への引数が渡す必要があるもの)と後不変式(関数の出力が渡す必要があるもの)があり、Adaはポストインバリアント。Ada 2012は型不変条件も提供するため、メソッドがAdaクラスで呼び出されるたびに、戻り前に型不変条件がチェックされます。

これは、優れたテストフレームワークが提供できる完全なテストの種類ではありませんが、言語が最適にサポートできる重要な種類のテストです。


2
エッフェルで少し仕事をし、アサーションの大規模なユーザーである私の経験では、契約上できることはすべて、多くのバグを発見するのに役立つということです。
Blrfl 14

2

強く型付けされた関数型言語の支持者の中には、これらの言語機能が単体テストの必要性を低減または排除すると主張する人もいます。

これの良い例は、F#for Fun and Profitのこちらこちらです

個人的には、私はまだ単体テストの価値を信じていますが、いくつかの有効なポイントがあります。たとえば、違法な状態がコードで表現できない場合、この場合の単体テストを書く必要がないだけでなく、不可能です。


2

ユニットテストに関しては強調されていないので、必要ないくつかの機能の追加を逃したと主張します。

たとえば、C#の単体テストは、主に属性を使用して実行されます。カスタム属性機能は、のようなもので、NUnitのようなフレームワークは、反復と競合することを可能にする豊富な拡張機構を提供理論をベースパラメータ化テストを。

これは私の2番目の主要なポイントに私を連れて行きます-私たちは言語にそれを焼くために良いテスト容易性を作るものについて十分に知りません。テストにおける革新のペースは他の言語構成よりもはるかに速いため、革新の自由を残すために、言語に柔軟なメカニズムを持たせる必要があります。

私はユーザーですが、TDDに夢中ではありません-場合によっては、特にデザイン思考を改善するのに非常に役立ちます。大規模なレガシーシステムには必ずしも有用ではありません。優れたデータと自動化による高レベルのテストは、強力なコード検査文化とともに、より多くの利益をもたらすでしょう。

その他の関連資料:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.