元々レガシーな環境でずっと作業してきていたがモダンな環境での作業となり、
少しずつ慣れてきてはいるものの、躓く点もまだまだ多い。
これまでに躓いた内容で特に学びになったなと感じているものを
復習も込めて記載してみる。
1.テストコード作成(junit5)
これまでの作業環境では、DBなどのテスト環境が必ず構築済みの状態であったため、
単体テストは基本的にプログラムを実際に実行してテストしていた。
しかし、今回はjunit5を使用してモックを用いたテストやテストの自動化を行った。
最初は「テストの自動化なんて便利そうだな~」くらいにしか思っていなかったが、
これが大きな罠であり、大きな反省点の一つで、
実際は今までの実装 + テストコードの実装が必要なことに後から気が付き、
これまでの思い描いていた実装のボリューム感から大きくズレてしまっていた…
また、「この観点でテストしたいけど、プログラムにどう起こせばいいんだ?」
となる部分が多かったことも、当初に思い描いていた実装時間よりも
大幅に時間がとられてしまった要因の一つだった。
例えば、以下のようなメソッドのテストをする場合、
テストコードはこんな感じになると思う。
テスト対象
public class TestClass {
public String testMethodA(String str){
return str + "_test";
}
}
テストコード
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class TestClassTest {
@Test
public void testTestMethodA() {
// テスト対象のオブジェクトを生成
TestClass testClass = new TestClass();
// テストケース1: 通常の文字列
String input1 = "hello";
String expected1 = "hello_test";
assertEquals(expected1, testClass.testMethodA(input1));
// テストケース2: 空文字
String input2 = "";
String expected2 = "_test";
assertEquals(expected2, testClass.testMethodA(input2));
// テストケース3: null を渡した場合
String input3 = null;
String expected3 = null; // null を渡すとそのまま返る想定
assertEquals(expected3, testClass.testMethodA(input3));
}
}
上記のようなテストコードは割と簡単に理解できたのだが、
以下のようなメソッドをテストしたいときに、
初心者の私は「???」となってしまった。
テスト対象
public class TestClass {
public String testMethodA(String str) {
return methodB(str + "_modified");
}
public String testMethodB(String str) {
return str + "_result";
}
}
testMethodAのテストをする際に、
「testMethodBが呼ばれた際の引数指定が正しいか」
を確認したいと思ったが、assertEqualsやassertThrowsくらいしか
まだ使ったことのなかった私はどうすれば…となってしまった。
その後、verifyを使えばよいことを知り、以下のようなテストコードで検証できた。
テストコード
@Test
public void testMethodA_callsTestMethodBWithCorrectArgument() {
// 期待される引数
String input = "testInput";
String expectedArgument = input + "_modified"; // testMethodB に渡される引数はこれ
// testMethodB をモックし、戻り値を指定
when(testClassToTest.testMethodB(expectedArgument)).thenReturn("dummyReturnValue");
// testMethodA を実行し、testMethodB が正しい引数で呼ばれるかを検証
testClassToTest.testMethodA(input);
// testMethodB が正しい引数で呼ばれたことを確認
verify(testClassToTest).testMethodB(expectedArgument); // 引数が正しいかを検証
// methodB が一度だけ呼ばれたことを確認
verify(testClassToTest, times(1)).testMethodB(expectedArgument);
}
verifyの存在は知っていたが、
「対象のメソッドが呼ばれた回数をチェックする」くらいの理解だったため、
正しい引数を指定して呼び出し回数を確認することで、
正しい引数で呼ばれていることを確認できるという発想がなかった…。
実際は上記のようなやり方で簡単にテストできる内容なので、
難しく考えずにもっと頭を柔らかくして、
あれをこう使えば検証できるんじゃね?といった考え方をすることで
無駄に時間をかけないようにしていきたい。
最初に比べて、テストコードも書けるようにはなってきたが、
テストコード作成に重きを置いてしまい、
肝心のテスト観点が漏れてしまうなんてこともあるので、
「このプログラムに必要なテスト観点は何なのか」という視点は
常に忘れないようにしていこうと思う。
2.MySQLとOracleの違い
過去にOracleのプロシージャ(PLSQL)を使用したことはあったが、
今回初めてMySQLのプロシージャで開発することになり、
「Oracleだとやり方がわかるが、MySQLのプロシージャだとどうやるの?」
ということがたくさんあった。
OracleからMySQLへの移行がモダンな環境になったというわけではないかもしれないが、
MySQLをOracleでいうなら…という情報をまとめてみる。
◆プロシージャ定義
- Oracle
-
PROCEDURE プロシージャ名 IS
BEGIN
END プロシージャ名;
- MySQL
-
CREATE PROCEDURE プロシージャ名(引数)
BEGIN
END ◯◯
◆プロシージャ内の変数
- Oracle
- DECLAREで宣言した変数がSQL文でも使用可能
- MySQL
-
DECLAREで宣言した変数はSQL文内では使用不可
@変数(宣言不要)であればSQL文内で使用可能
◆プロシージャ内のテキスト表示
- Oracle
-
DBMS_OUTPUT.PUT_LINE(‘テキスト表示’);
- MySQL
- SELECT‘テキスト表示’AS '';
◆動的SQLの実行
- Oracle
-
EXECUTE IMMEDIATE SQL文;
- MySQL
-
PREPARE プリペアド名 FROM SQL文;
EXECUTE プリペアド名;
DEALLOCATE PREPARE プリペアド名;
※プリペアドの解除
補足:MySQLの動的SQL内でシングルクォーテーションを使用している場合、
シングルクォーテーションの前に¥をつける必要がある
例:'テストデータID' → ¥'テストデータID¥'
◆ステートメントの処理件数
- Oracle
-
SQL%ROWCOUNT
- MySQL
- ROW_COUNT()
◆プロシージャの強制終了
- Oracle
-
END;
- MySQL
-
LEAVE ラベル名;
※ラベル名:BEGIN のようにラベル名を付ける必要あり
◆プロシージャ定義時の終了コマンド注意
- Oracle
-
END プロシージャ名;
- MySQL
-
DELIMITER ◯◯ ※;以外の終了コマンドを定義する
END ◯◯
DELIMITER ; ※最後に元に戻す
3.おわりに
まだまだ毎日学ぶことだらけで大変だが、
いつかこの記事を見て、
「あ~こんなこともわからないときあったな~」みたいな風に思えるように
日々インプットしてスキルアップしていきたい。