Go言語:自己文書化するためのテスト名
Google 社員で Go 言語のコミッターでもある @rakyll さんの 2017年2月3日のブログ記事『自己文書化するためのテスト名』が参考になった。ちょうどテストをしっかりと書くようになってきたところだったので非常にタイムリー。
SOURCE
Naming tests to self-document by @rakyll
Licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
翻訳
Go 言語はテスト名のつけ方を強制しません。 テストはコードの保守性に大きく貢献します。 正確性のチェックだけでなく、その使い方やコードの自己文書化にも役立ちます。その上、型や関数の責務を知るための最高の情報源です。良いテスト名をつけることで内部的なドキュメントとして役立ち、結果、コードの保守性も向上することになります。
入力や出力についてを名付けるのではなく、テストしているものの役割を強調してください。
func TestTitleIllegalChar(t *testing.T) {}
こう書かずに、編集時に不正な文字をエスケープする必要があることを説明するのです。
func TestTitleEscape(t *testing.T) {}
この名前の変更により、タイトルの不正な文字がどのように処理されるかを自己文書化できました。
時には包括的なテスト名にして、大きなテーブル駆動テストを書くことがあります(訳注: こういうコード)。 テーブル駆動テストを実行するなら、それらをサブテストに変換し、個々のケースに名前を付けることができます。 go test -v
を実行するとそれら名前が出力され、型や関数の仕様として機能します。
C++糞コンパイルエラー集
わかりにくいコンパイルエラーに悩まされて時間を無駄にすることがたびたびあり、6度目くらいでカッとなって記事にすることにした。順次追加していく。
Member reference base type 'User *const' is not a structure or union
以下は std::vector
の中から指定の name
に一致するユーザーの id
を取得するサンプルコード。
int findByName(std::vector<User*> users, const std::string& name) { auto user = std::find_if(users.begin(), users.end(), [name](User* u) { return u->getName() == name; }); return user->getId(); // ここでエラー }
正しいコードはこちら。
std::find_if
の戻り値がイテレータであることを知らずにオブジェクトだと誤解してるとハマる。ポインタにキャストすると値が取れる。
int findByName(std::vector<User*> users, const std::string& name) { auto itr = std::find_if(users.begin(), users.end(), [name](User* u) { return c->getName() == name; }); if (itr == users.end()) { return -1; } else { return (*itr)->getId(); } }
id
を返すコードだったため余計にエラー文がわかりづらい表現になっていた。もし User*
自体を返すコードだったら以下のようなエラー文になる。
No viable conversion from returned value of type 'std::__1::__wrap_iter<User**>' to function return type 'User *'
wrap_iter<User**>
となるためイテレータ型であることに早期に気づいたかもしれない。