🐡

CIだけ特定のソースコードをビルド、テストをしたくないとき

2023/01/04に公開

GithubAction便利ですよね。

ただ、一部のテストは外部システムとの連携やCIの仕様の都合上できなかったりして、
問題はないけどテスト自体が常に失敗するのでテスト自体をしたくないときもあります。

今回はdotnetのプロジェクトでCI上で一部のテストをしない方法を書きます。

これはifディレクティブとDefineConstantsを使うと実装できます。

ifディレクティブでCIで実行上はビルドを行わないという風に
定義するとこれは実装できます。

csproject

下記のようにCIにDefineを切ることで、ビルド時に ソースコードの無効と有効を切り替えます。

sample.csproj
	<PropertyGroup Condition="'$(CI)'=='true'">
		<DefineConstants>$(DefineConstans);CI</DefineConstants>
	</PropertyGroup>

csprojectは特に設定しなくても環境変数を$()で参照することができます。
Github actionでは環境変数CIがtrueに設定されるので、
GithubAction上ではCIというDefineが設定されるという事です。

$(DefineConstans);としているのは他にもDefineの設定が散っていると
上書きされるのでこのように書いています。

ソースコード

「テストコード自体をビルドしない」という形でテストしないか、
「ignoreという形でテストしないか」どちらかで実装します。

どちらが良いかは状況に併せて考えてください。
基本はignoreの方が良いかな?

先ほど定義したDEFINEを使って下記のように#ifでソースコードをビルドするか選択します。

ビルド自体しない場合

sample_test.cs
// #ifの内容がビルドされないため、テスト自体から見えない。
#if !CI
        /// <summary>
        /// Set EnvironmentVariable MachineTarget require Administrator authentication.
        /// </summary>
        [Test]
        [TestCase("bar")]
        public void Test6(string variable)
        {
            Guid machineguid = Guid.NewGuid();
            Assert.That(
                () => True.Deal.EnvironmentVariable.Environment.WinSetEnvironmentVariable(variable, machineguid.ToString(), EnvironmentVariableTarget.Machine)
                ,Throws.TypeOf<UnauthorizedAccessException>()
            );
        }
#endif

ignoreで無視する

sample_test.cs
        /// <summary>
        /// Set EnvironmentVariable MachineTarget require Administrator authentication.
        /// </summary>
        [Test]
        [TestCase("bar")]
// #ifの内容がCIだとIgnoreになるのでテストがスキップされる。
#if CI
        [Ignore("githubActionは管理者権限で実行されるためテストが難しい。とりあえずスキップ")]
#endif
        public void Test6(string variable)
        {
            Guid machineguid = Guid.NewGuid();
            Assert.That(
                () => True.Deal.EnvironmentVariable.Environment.WinSetEnvironmentVariable(variable, machineguid.ToString(), EnvironmentVariableTarget.Machine)
                ,Throws.TypeOf<UnauthorizedAccessException>()
            );
        }

こちらの方はビルドするので多かったらビルド時に時間がかかるかもしれない。

まとめ

.net framework系とdotnet系が混在してたり、
osごとの設定が混在すると ifディレクティブがどんどん複雑になります。

もしこれらを実装するなら運用時に混乱しないかも併せてよく考えてプログラミングスキルのある人が実装した方がいいと思います。

メタプログラミングになるので、スキル無いと運用時の難易度想像つかないしなこれ...

Discussion