4

特定の一連の構文規則に準拠するために必要な文字列出力を生成することを意図しています。無効な出力が生成される可能性を防ぐ目的で、C# の厳密な型指定を使用してその構文を適用するために、オブジェクト モデルを作成しました。

肯定的なテスト、つまり有効な C# が有効な出力を生成するテストを作成できます。私ができないことは、否定的なテストを実行することです。つまり、無効な出力を生成しようとすると、コンパイル時にエラーがスローされることを確認します。

明示的な例:

namespace Abstract
{
    public interface FooType { }
    public interface FooString : FooType { }
}

public interface Integer : Abstract.FooType { }    
public interface SingleLine : Abstract.FooString { }
public interface MultiLine : Abstract.FooString { }

public class Bar<T>
    where T : Abstract.FooType
{
    public Bar(string s) {
        // do stuff with s and T, where T is SingleLine or MultiLine
    }

    public Bar(int i) {
        // do stuff with i and T, where T is Integer
    }
}

public static class Foo
{
    public static Bar<T> Bar<T>(int i) where T : Integer {
        return new Bar<T>(i);
    }

    public static Bar<SingleLine> Bar(string s) {
        return new Bar<SingleLine>(s);
    }

    public static Bar<T> Bar<T>(string s) where T : Abstract.FooString {
        return new Bar<T>(s);
    }
}

それはすべて、私ができることです:

Foo.Bar<SingleLine>("some string");  // ok
Foo.Bar("another string");           // ok
Foo.Bar<MultiLine>("more\nstrings"); // still ok
Foo.Bar<Integer>(24)                 // also ok

// How to test these lines for compilation failure?
Foo.Bar<Integer>("no good");
Foo.Bar<MultiLine>(-1);

念のために言うと、私は VS2012 Express for Desktop を使用しています。

4

4 に答える 4

4

私はこれを行ったコードを非常に疑っています。ただし、クラスが特定の方法で動作するように誰かがコードを変更していないことを確認する単体テストを作成したい場合 (つまり、特定の方法で使用するとコンパイル エラーが発生しないようにする場合は、このコードで CodeDOM を使用できます)。仕方:

CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("mydll.dll");

parameters.GenerateExecutable = false;

CompilerResults results = 
    icc.CompileAssemblyFromSource(parameters, 
        String.Format(@"using System;

namespace Testing
{{
    class Program
    {{
        static void Main(string[] args)
        {{
            {0}
            Console.ReadLine();
        }}
    }}
}}
", "Foo.Bar<Integer>("no good");"));
Assert.AreNotEqual(0, results.Errors.Count);

基本的にプロバイダーを作成し、特定の DLL (おそらくどこにFooあるか) を参照することを伝えてから、コードを作成します (テキスト -- 中括弧は の区切り文字であるため、中括弧を 2 倍にしていることに注意してくださいString.Format)。クラスで(Mainexeを生成している場合を含む)、テキストをコンパイルします。Errorsコレクションでエラーが発生したことを確認できます。

于 2012-09-24T13:53:14.663 に答える
3

もちろん、コンパイルに失敗させたいコード スニペットを (文字列として、または .cs ファイルを文字列に読み込む) 作成し、CodeDomを使用して C# コンパイラを呼び出します。テストでは、コンパイラが失敗したことを確認するだけで済みます。必要に応じて、行番号のエラー メッセージなどを確認してください...正しいです。

もちろん、これはかなりの労力です。これによって実際にどれだけの利益が得られるかを評価する必要があります。他の開発者が使用するある種の API を開発していて、これが重要な機能であり、微妙な変更によって将来不注意で機能しなくなる可能性がある場合は、これを単体テストすることをお勧めします。そうでなければ、これはおそらく、わずかな報酬に対して多大な労力を費やすことになるでしょう (IMO)。

于 2012-09-24T13:32:16.613 に答える
0

Roslynはあなたにこのようなことをさせてくれます。おそらく.net5、C#6などに組み込まれるでしょう。ただし、これは基本的にコードdomと同等です。

于 2012-09-24T13:58:39.613 に答える
0

お気づきかもしれませんが、単体テストを実行するには、そのコードを正常にコンパイルする必要があるため、これは鶏が先か卵が先かという問題です。

これは、リフレクションを使用して API を呼び出すことで解決できます。互換性のない方法で型を呼び出している場合 (たとえば、型制約を使用した場合)、CLR は例外をスローします。

もう 1 つのオプションは、単体テストでテキストを使用してCode Domを使用する(または単に csc.exe をトリガーする) ことです。コンパイルを失敗させることで、テストを成功させることができます。

于 2012-09-24T13:30:39.850 に答える