
本記事は、ユニットテストの実行について解説します。
ユニットテストを実行する為には、テスト専用のクラスが必用になります。
もし、前回を確認していない場合は、下記から参照してください。
はじめに
本記事は、ユニットテストの実行編となります。
ユニットテストの実行には、下記手順が必用になります。
では、一つずつ確認していきましょう。
① テスト・クラスのエクスポート
テスト・クラスは、エクスポートして特定のディレクトリに配置します。
作成編で作成したテスト・クラスは下記4クラスになり、これらが「テスト・ケース」となります。
テストケースは、テストの目的や対象、関連性などに基づいてグループ化します。
このグループを、「テストスイート」と呼びます。
ObjectScriptでは、テストケース(テストクラス)を配置する「フォルダ」をテストスイートとしています。
今回は、サンプルなので複数のテストスイートを用意したいと思います。
<メインディレクトリ>
├ sampleTest
│ └ developer.export.UnitTest.cls
│
├ sampleObj
│ └ developer.export.UnitTestObject.cls
│
└ sampleFile
├ developer.export.UnitTestFile.cls
└ developer.export.UnitTestFileCheck.cls
この配置に合わせて、クラスをエクスポートします。
エクスポート実施
今回は、下記コマンドを利用してエクスポートしました。
自システムで運用する場合は、「clsNm, path」を適宜読み替えてください。
k err
s clsNm = "developer.export.UnitTest.cls"
s path = "D:\Temp\test\sampleTest\"_clsNm_".xml"
d $system.OBJ.Export(clsNm, path, "-d", .err) zw err
k err
s clsNm = "developer.export.UnitTestObject.cls"
s path = "D:\Temp\test\sampleObj\"_clsNm_".xml"
d $system.OBJ.Export(clsNm, path, "-d", .err) zw err
k err
s clsNm = "developer.export.UnitTestFile.cls"
s path = "D:\Temp\test\sampleFile\"_clsNm_".xml"
d $system.OBJ.Export(clsNm, path, "-d", .err) zw err
k err
s clsNm = "developer.export.UnitTestFileCheck.cls"
s path = "D:\Temp\test\sampleFile\"_clsNm_".xml"
d $system.OBJ.Export(clsNm, path, "-d", .err) zw errコマンド実行後、ディレクトリを確認してみます。
今回は、コマンドプロンプトから確認してみました。
D:\Temp\test>dir /s
ドライブ D のボリューム ラベルは ボリューム です
ボリューム シリアル番号は 5C07-9571 です
D:\Temp\test のディレクトリ
2025/05/17 10:56 <DIR> .
2025/05/17 10:56 <DIR> ..
2025/05/17 16:00 <DIR> sampleFile
2025/05/16 21:19 <DIR> sampleObj
2025/05/15 08:03 <DIR> sampleTest
0 個のファイル 0 バイト
D:\Temp\test\sampleFile のディレクトリ
2025/05/17 16:00 <DIR> .
2025/05/17 16:00 <DIR> ..
2025/05/18 09:44 1,253 developer.export.UnitTestFile.cls.xml
2025/05/18 09:44 3,946 developer.export.UnitTestFileCheck.cls.xml
2 個のファイル 5,199 バイト
D:\Temp\test\sampleObj のディレクトリ
2025/05/16 21:19 <DIR> .
2025/05/16 21:19 <DIR> ..
2025/05/18 09:44 2,546 developer.export.UnitTestObject.cls.xml
1 個のファイル 2,546 バイト
D:\Temp\test\sampleTest のディレクトリ
2025/05/15 08:03 <DIR> .
2025/05/15 08:03 <DIR> ..
2025/05/18 09:43 1,508 developer.export.UnitTest.cls.xml
1 個のファイル 1,508 バイト
ファイルの総数:
4 個のファイル 9,253 バイト
11 個のディレクトリ 478,038,736,896 バイトの空き領域エクスポートされているのが確認できました。
② メインディレクトリの設定
テストスイートを配置したルートパスを設定します。
先ほどの例であれば、「D:\Temp\test」が該当します。
ターミナルより下記コマンドを実行して、ルートパスを設定してください。
※ テストを実施するネームスペースに変更します。
zn [テスト実行ネームスペース]
s ^UnitTestRoot = "D:\Temp\test"③ テストコマンドの実行
ここまでの準備が終わったら、いよいよテストを実行します。
テストの実行コマンドは「RunTest」と「DebugRunTestCase」の2つあります。
// テスト後、ロードしたテスト・クラスを削除する
d ##class(%UnitTest.Manager).RunTest([testspec], [qualifiers], [userparam])
// テスト・クラスのロード・削除を行わない
d ##class(%UnitTest.Manager).DebugRunTestCase([testspec], [qualifiers], [userparam])両コマンドとも、引数が結構ややこしいので、要注意です。
RunTestの方は、エクスポートしたテスト・クラスをロードしてテストを実行した後、実施したテスト・クラスを削除します。
テスト・クラスの開発中で動作を確認したい場合は、「qualifiers」に「/noload/nodelete」を設定すると、テスト・クラスが削除されないので便利です。
DebugRunTestCaseは、メインディレクトリ直下にテスト・クラスを配置して実行します。
※ 実行リスト作成用のため
引数
testspec
実行するテスト項目を指定できます。
「テストスイート」「テストケース」「テストメソッド」は、「:」区切りで連結する事でテスト対象を絞り込むことが可能です。
例)特定のテストメソッドのみテストを実施したい場合
> テストスイート:テストケース:テストメソッド
また、複数のテストスイートやテストケースを実行したい場合は、「;」区切りで連結する事でテストを実施する事が可能です。
例)テストスイート配下の「テストケースA」「テストケースB」…を実行したい場合
「テストスイート:テストケース:テストメソッドA;テストケース:テストメソッドB;…」
| 指定内容 | 説明 |
|---|---|
| null | 全テストスイートを実行する |
| テストスイート | ※省略可 指定すると、直下の全テストケースを実行する |
| テストケース | ※省略可 指定すると、クラス内の全テストメソッドを実行する |
| テストメソッド | ※省略可 |
サンプル実行例
// 全テストスイート実行
d ##class(%UnitTest.Manager).RunTest()
// テストスイート指定
d ##class(%UnitTest.Manager).RunTest("sampleTest","/noload/nodelete/nodebug")
// developer.export.UnitTestFileCheck.clsのみを実行する
s testspec = "sampleFile:developer.export.UnitTestFileCheck"
d ##class(%UnitTest.Manager).RunTest(testspec,"/noload/nodelete")qualifiers
テスト実行時のオプションを指定します。
| 修飾子 | 説明 |
|---|---|
| /load | 規定値 テストをロードする |
| /unload | テストをロードしないで実行する |
| /run | 規定値 テストを実行する |
| /norun | テストをロードするが、実行しない |
| /delete | 規定値 テスト実行後、Iris or Cacheより該当クラスを削除する |
| /nodelete | テスト実行後に、該当クラスを削除しない |
| /recursive | 規定値 指定したディレクトリのサブディレクトリ内でテストを検索する |
| /norecursive | サブディレクトリは無視する |
| /debug | 最初のテストが失敗すると後続のテストを実行しない |
| /nodebug | 規定値 |
| /autoload | /autoload=[dir]を使用すると、テストは ^UnitTestRoot ディレクトリのサブディレクトリ[dir]からロードする |
| /display=all | 規定値 /display=allを使用すると、メソッドの実行時に拡張情報が表示される。 |
| /display=none | 限定された情報が表示される。 |
開発時のおすすめは「/noload/nodelete」です。
これを付け忘れて、何度か開発中のテストクラスが削除された事が何度かあります。
マジで辛いです。
皆様もお気をつけて!
userparam
「/log」を指定します。
指定するとターミナルへの出力が最小になり、下記ファイルへの出力を
<インストールディレクトリ>mgr\UNITTEST.LOG
これはこれで・・・ありかも?
テスト実行
では、いよいよテストを実行したいと思います。
今回は下記コマンドを使用しましょう。
d ##class(%UnitTest.Manager).RunTest(,"/noload/nodelete/nodebug")コマンドを実行すると、画面に大量の情報が表示されます。
===============================================================================
Directory: D:\Temp\test\sampleFile\
===============================================================================
sampleFile begins ...
ディレクトリにあるアイテムのリスト作成を開始 on 05/18/2025 16:49:57 '*.xml;*.XML;*.cls;*.mac;*.int;*.inc;*.CLS;*.MAC;*.INT;*.INC'
ファイル D:\Temp\test\sampleFile\developer.export.UnitTestFile.cls.xml を xml としてリストしています
ファイル D:\Temp\test\sampleFile\developer.export.UnitTestFileCheck.cls.xml を xml としてリストしています
リスト作成が正常に完了しました。
developer.export.UnitTestFile begins ...
TestFileDelete() begins ...
AssertTrue:ファイルの削除 ファイル名 = D:\Temp\txt\UnitTest.txt (passed)
AssertNotTrue:ファイルの削除(エラー) (passed)
LogMessage:Duration of execution: .000634 sec.
TestFileDelete passed
developer.export.UnitTestFile passed
developer.export.UnitTestFileCheck begins ...
TestFileCheck() begins ...
AssertFilesSame:'D:\Temp\txt\UnitCopyTest.txt'=='D:\Temp\txt\UnitCopyTestcopy.txt' (passed)
LogMessage:Duration of execution: .006184 sec.
TestFileCheck passed
TestFileNoCheck() begins ...
AssertFilesSame:'D:\Temp\txt\UnitCopyTest.txt'=='D:\Temp\txt\UnitCopyTestcopy.txt' (failed) <<==== **FAILED** sampleFile:developer.export.UnitTestFileCheck:TestFileNoCheck
File1 D:\Temp\txt\UnitCopyTest.txt
0:
>1:サンプルテキスト出力
2:
File2 D:\Temp\txt\UnitCopyTestcopy.txt
0:
>1:内容の不一致
2:
LogMessage:Duration of execution: .004963 sec.
TestFileNoCheck failed
TestQueryPlan() begins ...
AssertFilesSQLUnorderSame:'D:\Temp\txt\queryPlan1.txt'=='D:\Temp\txt\queryPlan2.txt' (failed) <<==== **FAILED** sampleFile:developer.export.UnitTestFileCheck:TestQueryPlan
plan 1 SELECT ID,ABO血液型,RH血液型,dele,patientId,カナ氏名,コメント,性別,漢字氏名,生年月日 FROM developer_data.Patient2 where 漢字氏名 like '九重山%' & ABO血液型 = 'O' & RH血液型 = '+' & 性別 = 1 /*#OPTIONS {"DynamicSQL":1} */ = SELECT ID,ABO血液型,RH血液型,dele,patientId,カナ氏名,コメント,性別,漢字氏名,生年月日 FROM developer_data.Patient2 where 漢字氏名 like '九重山%' & patientId between 11730001000 and 11730002000 /*#OPTIONS {"DynamicSQL":1} */
plan 1 Test the "=" condition on %SQLUPPER(ABO血液型), the "=" condition on %SQLUPPER(性別), the "=" condition on %SQLUPPER(RH血液型), the "NOT NULL" condition on %SQLUPPER(ABO血液型), the "NOT NULL" condition on %SQLUPPER(RH血液型), and the "NOT NULL" condition on %SQLUPPER(性別). = Test the ">=" condition on %SQLUPPER(patientId) and the "<=" condition on %SQLUPPER(patientId).
LogMessage:Duration of execution: .002952 sec.
TestQueryPlan failed
developer.export.UnitTestFileCheck failed
Skipping deleting classes
sampleFile failed
===============================================================================
Directory: D:\Temp\test\sampleObj\
===============================================================================
sampleObj begins ...
ディレクトリにあるアイテムのリスト作成を開始 on 05/18/2025 16:49:58 '*.xml;*.XML;*.cls;*.mac;*.int;*.inc;*.CLS;*.MAC;*.INT;*.INC'
ファイル D:\Temp\test\sampleObj\developer.export.UnitTestObject.cls.xml を xml としてリストしています
リスト作成が正常に完了しました。
developer.export.UnitTestObject begins ...
TestDelete() begins ...
AssertStatusOK:データの削除 name = サンプルテスト (passed)
LogMessage:Duration of execution: .000297 sec.
TestDelete passed
TestSave() begins ...
AssertStatusOK:データの登録 name = サンプルテスト (passed)
AssertStatusNotOK:登録時エラー エラー #5808: キーが一意ではありません: developer.test.TestData:idx:^developer.test.TestDataI("idx"," サンプルテスト") = (passed)
LogMessage:Duration of execution: .029102 sec.
TestSave passed
developer.export.UnitTestObject passed
Skipping deleting classes
sampleObj passed
===============================================================================
Directory: D:\Temp\test\sampleTest\
===============================================================================
sampleTest begins ...
ディレクトリにあるアイテムのリスト作成を開始 on 05/18/2025 16:49:58 '*.xml;*.XML;*.cls;*.mac;*.int;*.inc;*.CLS;*.MAC;*.INT;*.INC'
ファイル D:\Temp\test\sampleTest\developer.export.UnitTest.cls.xml を xml としてリストしています
リスト作成が正常に完了しました。
developer.export.UnitTest begins ...
TestAddition() begins ...
LogMessage:足し算関数の検証
AssertEquals:足し算関数検証(一致) 7 = 7 (passed)
AssertNotEquals:足し算関数検証(不一致) 28 = 7 (passed)
AssertSuccess:テスト成功 (passed)
LogMessage:Duration of execution: .00025 sec.
TestAddition passed
TestAdditionError() begins ...
LogMessage:足し算関数の検証(エラーケース)
AssertEquals:足し算関数検証(エラー) 6 = 7 (failed) <<==== **FAILED** sampleTest:developer.export.UnitTest:TestAdditionError
AssertFailure:テストエラー (failed) <<==== **FAILED** sampleTest:developer.export.UnitTest:TestAdditionError
LogMessage:Duration of execution: .000658 sec.
TestAdditionError failed
developer.export.UnitTest failed
Skipping deleting classes
sampleTest failed
Use the following URL to view the result:

http://XXX.XXX.XXX.XXX:52773/csp/sys/%25UnitTest.Portal.Indices.cls?Index=59&$NAMESPACE=SAMPLE
Some tests FAILED in suites:
sampleFile,sampleTestこれらの情報は、次回確認しましょう。
おわりに
いかがだったでしょうか。
今回はユニットテストの実行について解説しました。
ユニットテストはただ書いて終わりではなく、「いつ、どのタイミングで実行するか」が非常に重要だと思います。
これについては現場や開発スタイルによって意見が分かれる部分もあり、一定の議論があります。
| 状況 | 期待できる効果 |
|---|---|
| 開発中 | 開発者が修正/追加する度に、開発環境でユニットテストを実行する。 不具合の早期発見が期待できる。 |
| コミット/プッシュ前 | コミット/プッシュ直前に、自動でユニットテストを実行する。 不具合を含んだソースがリポジトリに入るのを防ぐことができる。 |
| CIでの自動テスト | プルリクエスト等で自動でユニットテストを実行する仕組みを構築する。 アプリ全体の品質を保全できる。 |
| 定期実行 | 定期的に全ユニットテストを実行する。 アプリ全体の品質を保全できる。 |
ユニットテストの実行は、複数の状況で実行できるように設計すると良いかもしれません。
ObjectScriptは、タスクスケジュールやInteroperabilityがあるので、それらを活用してもよいと思います。
さて、次回はユニットテストの結果を確認しましょう。
ObjectScriptが用意している専用の画面は、かなり癖があるので注意が必要です。


