PHPUnitの後処理でテーブルをTRUNCATEする

PHPUnitでテスト用のレコードを作成するのだが、テストで作成したレコードが残ってしまい再度テストを行うと失敗するという現象に遭遇した。

以下のようにAppTestCase を作成してカスタマイズしている。
setup() メソッドで datasets ディレクトリにymlファイルがあればその内容でデータを作成している。

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
class AppTestCase extends PHPUnit_Extensions_Database_TestCase
{
static private $_pdo = null;
private $_conn = null;
private $_dataSet;
private $_obj;

protected function setUp()
{
$fixturePath = 'datasets/' . get_class($this) . '/' . $this->getName() . '.yml';
if (file_exists($fixturePath)) {
$this->_dataSet = new PHPUnit_Extensions_Database_DataSet_YamlDataSet($fixturePath);
} else {
$this->_dataSet = new PHPUnit_Extensions_Database_DataSet_DefaultDataSet();
}
parent::setUp();
}

public function getConnection()
{
if ($this->_conn === null) {
if (self::$_pdo == null) {
self::$_pdo = new PDO(DB_DSN, DB_USER, DB_PASSWD);
}
$this->_conn = $this->createDefaultDBConnection(self::$_pdo, DB_DBNAME);
}
return $this->_conn;
}

public function getDataSet()
{
return $this->_dataSet;
}
}

PHPUnitのドキュメントにはTRUNCATEが実行されると書いてあるが、TRUNCATEはテストデータが作成される前に行われるので最後に作成されたレコードは残ってしまう。

MySQLサーバのクエリログは以下。
ドキュメント通りデータが作成される前にTRUNCATEが実行されている。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2016-11-08T07:47:26.906619Z        26 Connect   root@192.168.75.91 on app_test using TCP/IP
2016-11-08T07:47:26.907174Z 26 Query SET NAMES 'ujis'
2016-11-08T07:47:27.136497Z 27 Connect root@192.168.75.91 on app_test using TCP/IP
2016-11-08T07:47:27.248506Z 28 Connect root@192.168.75.91 on using TCP/IP
2016-11-08T07:47:27.249034Z 28 Init DB app_test
2016-11-08T07:47:27.256189Z 28 Init DB app_test
2016-11-08T07:47:27.256837Z 28 Query select * from users
2016-11-08T07:47:27.258065Z 28 Init DB app_test
2016-11-08T07:47:27.258473Z 28 Init DB app_test
2016-11-08T07:47:27.331138Z 27 Query SET FOREIGN_KEY_CHECKS = 0
2016-11-08T07:47:27.331548Z 27 Query TRUNCATE `users`
2016-11-08T07:47:27.349437Z 27 Query SET FOREIGN_KEY_CHECKS = 1
2016-11-08T07:47:27.349922Z 27 Query SHOW COLUMNS FROM `users`
2016-11-08T07:47:27.350848Z 27 Query SHOW INDEX FROM `users`
2016-11-08T07:47:27.351590Z 27 Query INSERT INTO `users`
(`account_id`, `domain`, `created_at`)
VALUES
('1', ‘example.com', '2016-11-02 18:40:10')
2016-11-08T07:47:27.354645Z 28 Init DB app_test
2016-11-08T07:47:27.355089Z 28 Init DB app_test
2016-11-08T07:47:27.355386Z 28 Query select * from users
2016-11-08T07:47:27.360299Z 26 Quit
2016-11-08T07:47:27.391481Z 27 Quit
2016-11-08T07:47:27.431965Z 28 Quit

テストを実行した後にTRUNCATEするには getTearDownOperation メソッドを追加する。

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
40
class AppTestCase extends PHPUnit_Extensions_Database_TestCase
{
static private $_pdo = null;
private $_conn = null;
private $_dataSet;
private $_obj;

protected function setUp()
{
$fixturePath = 'datasets/' . get_class($this) . '/' . $this->getName() . '.yml';
if (file_exists($fixturePath)) {
$this->_dataSet = new PHPUnit_Extensions_Database_DataSet_YamlDataSet($fixturePath);
} else {
$this->_dataSet = new PHPUnit_Extensions_Database_DataSet_DefaultDataSet();
}
parent::setUp();
}

public function getConnection()
{
if ($this->_conn === null) {
if (self::$_pdo == null) {
self::$_pdo = new PDO(DB_DSN, DB_USER, DB_PASSWD);
}
$this->_conn = $this->createDefaultDBConnection(self::$_pdo, DB_DBNAME);
}
return $this->_conn;
}

public function getDataSet()
{
return $this->_dataSet;
}

// テスト後にテーブルをTRUNCATEする
public function getTearDownOperation()
{
return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
}

あとは各UnitTestのtearDownメソッドで parent::tearDown() を実行する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class SampleTest extends AppTestCase
{
public function setUp()
{
parent::setUp();
}

public function tearDown()
{
parent::tearDown();
}
.....
}

以下が変更後のMySQLのクエリログだ。
最後にTRUNCATEが実行されている。

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
2016-11-08T08:43:49.367260Z       120 Connect   root@192.168.75.91 on app_test using TCP/IP
2016-11-08T08:43:49.367966Z 120 Query SET NAMES 'ujis'
2016-11-08T08:43:49.626685Z 121 Connect root@192.168.75.91 on app_test using TCP/IP
2016-11-08T08:43:49.743978Z 122 Connect root@192.168.75.91 on using TCP/IP
2016-11-08T08:43:49.744418Z 122 Init DB app_test
2016-11-08T08:43:49.751453Z 122 Init DB app_test
2016-11-08T08:43:49.752239Z 122 Query select * from users
2016-11-08T08:43:49.758493Z 122 Init DB aap_test
2016-11-08T08:43:49.759944Z 122 Init DB app_test
2016-11-08T08:43:49.760656Z 122 Query select * from users
2016-11-08T08:43:49.828928Z 121 Query SET FOREIGN_KEY_CHECKS = 0
2016-11-08T08:43:49.829372Z 121 Query TRUNCATE `users`
2016-11-08T08:43:49.852672Z 121 Query SET FOREIGN_KEY_CHECKS = 1
2016-11-08T08:43:49.853435Z 121 Query SHOW COLUMNS FROM `users`
2016-11-08T08:43:49.854605Z 121 Query SHOW INDEX FROM `users`
2016-11-08T08:43:49.855462Z 121 Query INSERT INTO `users`
(`account_id`, `domain`, `created_at`)
VALUES
('1', ‘example.com', '2016-11-02 18:40:10')
2016-11-08T08:43:49.863268Z 122 Init DB app_test
2016-11-08T08:43:49.864301Z 122 Init DB app_test
2016-11-08T08:43:49.864678Z 122 Query select * from users
2016-11-08T08:43:49.869473Z 121 Query SET FOREIGN_KEY_CHECKS = 0
2016-11-08T08:43:49.869882Z 121 Query TRUNCATE `users`
2016-11-08T08:43:49.885689Z 121 Query SET FOREIGN_KEY_CHECKS = 1
2016-11-08T08:43:49.888006Z 120 Quit
2016-11-08T08:43:49.914728Z 121 Quit
2016-11-08T08:43:49.941933Z 122 Quit

StudyPlusを使った英語の勉強をはじめて5ヶ月目の記録

StudyPlusに英語の勉強を記録し始めて5ヶ月。
幸運なことに継続して学習を続けることができている。

勉強時間は128時間(累計)。
覚えた単語数は4600。
前回が3500だったので1ヶ月で1100、語彙数が増えた。
だんだん単語が覚えやすくなってきた感じがしている。

前回から変わった点としては洋書を読み始めたことがあげられる。
Kindle Unlimitedを契約したので、洋書の入手に事欠かなくなったからだ。

最近読んだのは以下の本。
英語の効果的な勉強法を英語で勉強できるので1粒で2度おいしい。

Kindle Unlimitedは洋書が132万冊あるので、これから存分に活用させてもらうつもりだ。
ちなみにLearn Englishによると、知っている映画の本を読むのがリーディングに最適だそうだ。

また、洋画を観ることも始めた。
こちらはまだ習慣化するところまで至っていないが、基本的には同じ映画のセリフを覚えるまで何回も繰り返し観るということをやろうと考えている。
題材はThe Devil Wears Plada(プラダを着た悪魔)だ。
これにした理由はニューヨークを舞台とした映画が良いと思っていて(これについては完全なる好みの問題)たまたま手元にあったのがプラダを着た悪魔だった。

過去の英語の勉強記録

Slackで定期的にRubotyに仕事をさせる

ChatOpsの一環としてSlackにRubotyを常駐させているのだが、Rubotyに定期的にタスクを実行させたいことがあった。
最初はruby-cronを使ってみたのだが、Slackだとうまく動かなかった。
具体的にはジョブの登録はできるのだがジョブの実行(通知)がされない。

うまくいかなかったのでSlackのリマインダー機能を使ってみることにした。
Slackのリマインダー機能を使うと Reminder: と言うプレフィックスが入るのでRubotyが反応せず、こちらもうまくいかなかった。

最終的にはcronでスクリプトを定期実行させることにした。
Slackに通知するスクリプトを作って、それをcronで定期的に実行させる。
メッセージを拾ったRubotyがタスクを実行するといった感じだ。

サンプルコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require "faraday"

username = 'your name'
channel = 'your channel'
slack_token = 'your slack token'
icon_url = 'your icon url'

body = {
username: username,
channel: channel,
icon_url: icon_url,
text: "ruboty ping"
}

Faraday.new('https://slack.com') do |c|
c.request :url_encoded
c.adapter Faraday.default_adapter
end.post("/api/chat.postMessage?token=#{slack_token}", body)

これでRubotyに定期的に仕事をさせることができるようになった。

RubyGems.orgに反映させるRakeタスクの紹介

Gemを更新した場合はRubyGems.orgに反映させる手続きが必要だ。
Gemを更新することはそんなに多くないので(私の場合)よく手順を忘れてしまう。
毎回手順を探すのはストレスなので以下のようなRakeタスクを作成した。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec

namespace "gem" do
desc 'Build a gem package'
task :build do
sh "gem build your_gem_name.gemspec"
end

desc 'Push a gem package'
task :push do
Rake::Task["gem:build"].execute
sh "gem push your_gem_name-#{YourGemName::VERSION}.gem"
end
end

公開する時は以下のタスクを実行すればいい。

1
$ rake gem:push

以下は実際のソースだ。
参考にしてほしい。

Kindle Unlimitedの冊数は図書館並みだった

今更ながらKindle Unlimitedを使ってみた。
すでに承知の方が大半だろうが、Kindle UnlimitedはKindle本の読み放題サービスだ。
月額980円でKindle Unlimitedに登録されている本を読むことができる。
ちなみに現在登録されている本はおよそ13万冊。
この数は私が利用する糸島市図書館のおよそ2倍だ。

ちなみに13万冊というのは日本で出版されている本の数で洋書は含まれていない。
洋書は10倍にあたる132万冊を読むことができる。
132万冊といえば全国で6番目に蔵書数が多い滋賀県立図書館に匹敵する。

洋書を手に入れる場所は日本だと限られているが、Kindleを使えば大型の図書館の蔵書数に匹敵する洋書を読むことができる。
また、Kindleアプリには英語の翻訳機能が搭載されているので、不明な単語があれば即座に意味を確認することもできる。

使ってみて3週間ほど経つが、月額980円をペイするには十分すぎるクオリティだと思う。
Kindleは各プラットフォームにアプリが用意されており、Kindleがなくても読むことができる。
自分はKindle Fireを持っているがKindle Fireを使うことはあまりなく、iPhoneやMacで読むことの方が多い。

Kindle Unlimitedで読めるKindle本は以下で確認できる。