rails test ではまった話。テスト環境のデータベース構築について

railsでの開発も、さて一段落。というか、いろいろな所に落ちているコードの組合せだけではなく、自分でロジックを作って行く必要がぼちぼちとでてきました。

そこで、必要になるのがテストコード。いつもの様に、チュートリアルを読んでコピペをして「実行」をしたところ偉いことが起きてしまいました。

# ActiveRecord::StatementInvalid: PG::UndefinedTable が。。。

## testの作り方 in Rails 5.2

modelとかcontrollerとかを `rails generate` で作っていたら。。という前提ですが。。

1. testフォルダ以下に生成されている model/**_test.rbを開く
2. ActiveSupport::TestCase を継承している **Testクラスにテストメソッドを記載する (test "check my hat" do とか。これは def test_check_my_hat doと同値でマクロで定義されているらしい。。)
3. コンソール上で、実行したいテストを含むrbファイルを実行する
    * rails test test/model/**_test.rb
   
以上。3のテストメソッドの中に assert ** と色々と評価する式を書いてあげるとそのtrue/falseが結果として集計されます

今回書いたテストはこちら

```
	test "check my hat" do
		assert true
	end
```
ただ、「成功」を返すだけのものです

## で起きたエラーは以下

```
Error:
HatTest#test_check_my_hat:
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "adresses" does not exist
LINE 8:                WHERE a.attrelid = '"adresses"'::regclass
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
                     c.collname, col_description(a.attrelid, a.attnum) AS comment
                FROM pg_attribute a
                LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
                LEFT JOIN pg_type t ON a.atttypid = t.oid
                LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
               WHERE a.attrelid = '"adresses"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum
```

## さて今更テストの環境を確認してみる

### どこのデータベースが利用されるのか？

テーブルがないとかrelationがないとか言われているので、データベースが壊れているのかなと推測したわけです。

### testでは RAILS_ENV=testが利用される

config/environments/以下の test.rb
config/database.yml の記載を確認

手抜きをしたいがために、developmentとtestのデータベースを同じにしていたのがいけないのか？
でも、ちょっと動かしただけで盛大にエラーが出るのはなぜ？

### dbconsoleにつないでみる

`rails dbconsole -e test' を実行
Passwordを聞かれたので、「上手く値がdatabase.ymlから取得出来ない？」とか思ったけど、これは正常の動作ですね。。。

```
vagrant@vagrant:/var/www/html/skillconnect$ rails dbconsole -e test
/home/vagrant/.rbenv/versions/2.4.4/bin/ruby: warning: shebang line ends with \r may cause a problem
Password:
psql (10.4 (Ubuntu 10.4-2.pgdg16.04+1))
Type "help" for help.

skillconnect=>
```

postgresのコンソールが動きました。
これは上手く動いています。
久々だったので、終了方法を忘れていましたが、`\q`で終了です

### よくわからないのでテスト環境のデータベースを作って見る

問題の切り分けをするために、「推奨されたやり方」を試みて見ました。

すなわち、テスト用のデータベースを作成して見ます。

意外とやり方がまとまったページが見つからなかったのですが、手順は以下の通り

1. データベース上（今回の場合はpostgresql)にユーザー（ロール）を作成する
2. スキーマを作成する (ユーザーに管理者権限があるならば、`rails db:create RAILS_ENV=test` により、database.ymlに基づいたスキーマが作成される
3. `rails db:reset RAILS_ENV=test` により、db:migrateとdb:seedをまとめて行う。個々に行う場合は `rails db:migrate RAILS_ENV=test` `rails db:seed RAILS_ENV=test` で行う (resetは実際にはスキーマのdropとcreateが行われるので、実はdb:createもいらないかも。。)

それでも、エラーは解消されない・・・

## 原因は

エラーメッセージをよく見ると relation "adress" does not existとなっていた。
こいつは、昔作ったものの、綴りが間違えているので、モデルを作り直したことを思い出す。
当然、現在は adressというrelationは存在しない。

### fixtures/adress.yml でした。。

rails generate modelでは test/model以下の **_test.rbの他に、fixtures/**.ymlも自動生成されていたのでした。
モデルを作り直したとき、app/model/adress.rb はファイル名を直接書き換えてしまったのですが、実は悪さしていたのはそのadress.yml。

rails testの本体？である、test/test_helper.rbを見ると（多分デフォルトの状態）

```
class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
end
```
とfixturesが自動で読み込まれるとのこと。
このfixturesはモデルに対してテストデータを作成するファイルですね。

adress.ymlファイルが存在して、デフォルトのテストデータも残っていたため、丁寧にもそのデータを 'adresses'テーブルに突っ込むことを試みていたのでした。

それが、`ActiveRecord::StatementInvalid: PG::UndefinedTable` の正体でした。。 

assert trueを返すだけでもいろいろなドラマがあるのですね。。。