判定の方式でフォルダを分けている(#610)。
実行と判定の手順は TESTING.md(Golden / NUnit)と
SMOKETEST.md(Else の一部)が一次情報。
DB を使うテスト(
TestDataAccess/TestPublicDb)のコンテナは、LocalServicesOnDocker のCHEATSHEET.mdに従って扱う。 メモリを節約しないと、最悪の場合、コンテナがシステムごとハングさせる。 必要なものだけを名前で起動し、必須でないものを同時に複数起動せず、使い終わったら止める (要点はTESTING.mdの冒頭)。
| フォルダ | 判定の方式 | 回すもの |
|---|---|---|
Golden/ |
ゴールデン ファイル方式。 出力を、コミット済みの Result*.txt と比較する(後退テスト) |
2_RunAllTests.ps1 |
NUnit/ |
NUnit による単体テスト。テスト自身が合否を出す | 2_RunAllTests.ps1 |
Else/ |
上のどちらでもないもの(自分で合否を出す EXE、GUI、目視の確認、補助ファイル) | 一部は 3_SmokeTest.ps1 |
上位: Frameworks/ANALYSIS.md(全体の俯瞰・ビルド)
| 区分 | 名前 | 内容 | 専用の文書 |
|---|---|---|---|
Golden |
TestCode |
コンソール EXE。Program.cs から Test*.Root() を順に呼ぶ。期待値は Result48.txt / ResultCore100.txt と比較。DB には接続しない |
README.md |
Golden |
TestDataAccess |
データ アクセスのテスト(#520)。TestCode と同じ構成だがDB に接続する。/MODE で対象の DBMS を切り替える(既定は SQL Server のみ) |
README.md |
Golden |
TestBatch |
バッチ起動の確認 | — |
Golden |
EncAndDecUtilCUI |
暗号・署名ユーティリティの CUI 確認。結果ファイルは net48 / net10.0 / Linux の 3 つ。jose-jwt との相互運用も見る |
Public/Security/ANALYSIS.md 8 節 |
NUnit |
TestPublic |
Public 層の単体テスト(#610)。1 つの csproj で net48 / net10.0 をマルチ ターゲットにする。テスト自身が合否を出す |
本書 |
NUnit |
TestPublicNLog |
LogIF を NLog に切り替えた状態のテスト(#610)。使うライブラリはプロセスで 1 回しか決まらないため、別プロジェクト(別プロセス)にしている |
本書 |
NUnit |
TestPublicDb |
Dam のクロス DB テスト(#610)。DB に接続するので別プロジェクト。SQL Server は必須、他の DBMS は接続できなければスキップ | 本書 |
Else |
TestTransmission |
通信制御の接続オプション(#546)。オリジンとプロキシを自前で立て、CallController から呼んで、要求に反映されているかを見る。期待値ファイルを持たず、自分で合否を出す(疎通テストから呼ばれる) |
SMOKETEST.md 3 節 |
Else |
TestWebAPIClient |
Web API の非ブラウザ クライアント(疎通テストから呼ばれる) | SMOKETEST.md |
Else |
TestLog |
ログ出力の確認(log4net / NLog、1〜3) | — |
Else |
EncAndDecUtil |
暗号・署名ユーティリティの GUI 確認 | — |
Else |
LaunchJson |
リモート デバッグ用の launch.json の例(テストではない) |
— |
TestCode と TestDataAccess は専用の README.md を持つ。
「何をテストしているか」「ケースを書き足すときの決まり」「ケース設計の根拠」はそちらが一次情報。
TESTING.md は Golden と NUnit を含む全体の運用を扱い、この詳細は持たない。
Golden のテストを書き足す前に TestCode/README.md を読むこと。
結果ファイルとの比較で判定するため、環境で変わる値を出してはならないという制約がある
(例外はメッセージを出さず型名だけ、日時は固定値、csproj は net48 / core100 の両方を直す)。
テスト プロジェクトはフレームワークを ProjectReference ではなく HintPath で参照する
(net10.0 は Infrastructure/Build_netcore100/net10.0/*.dll、net48 は Infrastructure/Build_net48/*.dll。
Else/TestLog だけは Infrastructure/Build/*.dll で、4_Build_CopyAssemblies.bat の後でないとビルドできない)。
→ フレームワークを先にビルドしないと、テストは古い DLL を見る。
Golden は net48 / core100 の 2 プロジェクトが ..\*.cs を Link で共有する(実体は 1 つ)。
NUnit は 1 つの csproj でマルチ ターゲットにする(下の「NUnit のテストを書き足すとき」)。
「何をテストするか」ではなく「どう合否を決めるか」で置く。
- 出力を期待値ファイルと突き合わせる →
Golden/2_RunAllTests.ps1の対象に加える。環境で変わる値を出してはならない (Golden/TestCode/README.md) - テスト フレームワークの Assert で判定する →
NUnit/ - それ以外 →
Else/
NUnit/TestPublic は Touryo.Infrastructure.Public の単体テスト。
名前空間ごとにフォルダを切り、クラスごとに <クラス名>Tests.cs を置く(例: Str/StringCheckerTests.cs)。
y_Build_TestCode_NUnit.bat … ビルド → net48 / net10.0 で実行 → TestResults\*.trx
.\2_RunAllTests.ps1 -Only NUnit
- 1 つの csproj で net48 / net10.0 をマルチ ターゲットにしている。
Golden のように 2 プロジェクトへ
Linkで共有する作りではない - TFM で結果が違う箇所は
#if NETCOREAPPで書き分け、テスト名と<summary>に違いを書く。 例:StringConverterは net48 が VB のStrConv、.NET が Zipangu で、実装が違う - csproj で
LangVersionをlatestにしている。 net48 の既定(C# 7.3)では、 NUnit 4 のAssert.Throws(() => ...)がTestDelegateとActionの間で曖昧になり、 net48 だけコンパイルに失敗する。new TestDelegate(...)で逃げると、 NUnit 4.6 では旧形式の警告(CS0618)になる。素直にラムダで書けばよい - カルチャに依存する部品(数値・日付の文字列化)は
[SetCulture("ja-JP")]で固定する - 環境変数・カルチャなどプロセスの状態を変えたら、
[TearDown]で戻す - ファイルを書くテストは、
%TEMP%\OpenTouryoNUnit\<GUID>を作業フォルダにし、[TearDown]で消す - .NET では、設定を読む部品の前に
GetConfigParameter.InitConfigurationが要る。TestSetup.cs([SetUpFixture])が全テストの前に空の構成を与えている。 設定を読むと気付きにくい部品もある(例:EmbeddedResourceLoaderは内部でAzureキーを読む)。 呼び忘れるとNOT_INITIALIZEDのArgumentExceptionになり、Existsのように 例外を握る API では 黙って false が返る - テストに設定値を与えるときは、net48 の
App.configと .NET のTestSetup.csの両方に同じ値を書く。 いまはFxLog4NetConfFile(NUnitLogConf.xml。LogIFのテストが使う)だけ LogIFの NLog 側はTestPublicNLogに書く。LogLibは静的コンストラクタで 1 回だけ読まれ、同じプロセスでは log4net のまま変えられないため、別プロジェクトにしている (dotnet testはテスト アセンブリごとに別プロセスで動かす)。 プロセスの状態を変える設定が要るテストは、同じやり方でプロジェクトを分ける- プロジェクトを足したら、
TestPublic.slnに加え、y_Build_TestCode_NUnit.batのcall :RunTestsと2_RunAllTests.ps1の対象に足す。 バッチの.slnのパスは変数を使わずに書く(SelectTargets.ps1がそこから 「このバッチが建てるもの」を読むため。%VAR%を含むと解決できず、黙って外れる) - フォルダ名を
Logにしない。.gitignoreの[Ll]og/(ログ出力先の除外)に当たり、 中のテストが黙って Git から外れる(ビルドは通るので気付かない)。ログのテストはLogging/に置く。 新しいフォルダを作ったらgit statusで未追跡に出ることを確かめる - OS の状態を変えるテストは、権限が無ければ
Assert.Ignoreでスキップし、[TearDown]で必ず戻す。 例:Logging/CustomEventLogTests.cs(net48 専用。専用のログOTNUnitLogを作って消す。管理者のみ)。CustomEventLog.Deleteはソースが属するログごと消すので、既存のログのソースを渡さない - Db のテストは DB に接続しない。
SQLUtilityと、DamSqlSvr.ExecGenerateSQL(組み立てた SQL を返すだけで、接続を使わない)で、動的パラメタライズド クエリのタグを確かめる。 XML はSetSqlByCommandに文字列で渡せる(動的かどうかは中身で決まる)。 実行して件数を見るものは Golden のTestDataAccess(DB が要る) - DB に接続するテストは
TestPublicDbに書く。 同じテストを DBMS ごとに回す(TestFixtureSource)。 DBMS の差(Dam・接続文字列・囲い文字・パラメタ記号・型名)はDbProvider.csに集める。 既存の表は使わず、一意な名前の表を作って最後に落とす。数値はConvertで比べる(Oracle の NUMBER は decimal)。 Oracle は空文字を NULL として扱うので、空文字を値に使わない - 埋め込みリソースの検証には、
OpenTouryo.Publicに埋め込まれているXml/TestXml.xml/Xml/TestXsd.xsdを使える - 証明書が要るテスト(
Security/)は、正本(root/files/resource/X509)を csproj のリンクで出力先のX509に複写して使う (Security/TestCertificates.cs。*.pfxのパスワードはtest)。 読み込みのフラグはExportableだけにする(MachineKeySetは管理者でないと失敗することがある)。 net10.0 はX509Certificate2のコンストラクタが旧式扱い(SYSLIB0057)なので、TestCertificates.LoadCer/LoadPfxを使う - CNG(
ECDsaCngなど)を使うテストは[Platform("Win")]を付ける。 Windows 以外では動かない (Public/Security/ANALYSIS.md3.1 節) - フレームワークは
HintPathで参照する。Publicが使うパッケージは、 テストで通る範囲だけ csproj にも並べる(推移的依存が効かないため) - 読み違えやすい挙動を見つけたら、それ自体をテストにする
(例:
IsNumbers("")は true、IsNumeric("")は false)。 不具合と思われるものは、テストで固めずに報告する
どこを書き足すかは、カバレッジの低いところから選ぶ。 判定には使わない。
2_RunAllTests.ps1 が net10.0 の結果でアセンブリごとの行カバレッジを表示し、
coverage.cobertura.xml(クラス・行の単位)の場所を出す。
計測するのは OpenTouryo.* だけ(coverlet.runsettings)。
Golden のテストが通している行は数えていない。 コンソール EXE の出力比較であり、 カバレッジの計測には載っていない。低い数字は「NUnit で確かめていない」という意味である。
フォルダの深さが変わると、相対パスが全部ずれる。 移動した時に直したのは次のとおり。
| 場所 | 相対パスの基点 |
|---|---|
*.csproj の HintPath |
プロジェクトのフォルダから Infrastructure\Build_* へ(Golden/TestCode/net48 からは ..\..\..\..\Infrastructure) |
README.md のリンク |
README の置き場所から root/programs/*.md へ |
root/programs/CS/y_Build_Test*.bat |
root/programs/CS から(Frameworks\Tests\Golden\...) |
2_RunAllTests.ps1 の Result |
この Tests フォルダから |
st_Targets.ps1 の Exe |
root/programs/CS から |
.gitignore |
リポジトリのルートから(テスト証明書の作業用コピー) |
期待値は
git show HEAD:<パス>で取る。 移動をコミットするまでは、 HEAD に新しいパスが無いため2_RunAllTests.ps1は「HEAD から取得できません」になる。 コミットの前に確かめるなら、旧パスの HEAD 版とCompareResult.ps1で比べる。