Is there a way to assert that a block of code doesn't compile?

In MS Test, is there a way to assert that a block of code isn't compiling? Let's say I have an object that I want to be a single. I probably want to make sure that this object has no public constructors. Is there a way to do something like this?

Action create = { new Logger("abc.txt") };
Assert.CompilerError(create);

      

I can do this with Reflection, but I was curious if there is a way to assert that the code does not actually compile. This is how I would do it using Reflection:

[TestMethod]
public void OnlyPrivateConstructors()
{
    var flags = (System.Reflection.BindingFlags)int.MaxValue; //all flags
    var constructors = typeof(Logger).GetConstructors(flags);

    foreach (var item in constructors)
    {
        Assert.IsTrue(item.IsPrivate);
    }
}

      

+3


source to share


3 answers


MS test runs the compiled code. If the code does not compile, it cannot be tested.

Perhaps you can do this with Roslyn by creating a line with the appropriate block of code and then asking Roslyn to compile it.

http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx



Pre-roslyn, you can create a file containing your code block and then run csc against it with System.Diagnostics.Process or the like, but thus more trouble than it costs.

I'd stick with reflection, but since internal or protected constructors also allow singleton pattern violations, I would Assert.IsTrue(item.IsPrivate)

.

I would also have a test for Assert.IsTrue(typeof(Logger).IsSealed)

. It looks like a bit of belts and suspenders, but there and so.

+2


source


You can use CSharpCodeProvider to try and compile your code on the fly, but as Phog says, its probably more of a problem than it's worth:



        var compiler = new CSharpCodeProvider();

        string source = "using DLLBeingTested; \r\n" +
                        "public class DoIt {\r\n" +
                        "public void DoSomething() {\r\n" +
                        "var x =  new Logger(\"abc.txt\");\r\n" +
                        "}}" +
                        "";

        var loc = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);


        var cp = new CompilerParameters(new[] { Path.Combine(loc, "DLLBeingTested.dll") });
        cp.ReferencedAssemblies.Add("System.dll");
        cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");

        var assm = compiler.CompileAssemblyFromSource(cp, source);

        bool foundExpectedError = false;
        foreach (var err in assm.Errors)
        {
            if (err.ToString().Contains("CS0143"))
            {
                foundExpectedError = true;
            }
        }

        Assert.IsTrue(foundExpectedError);

      

+1


source


I think you are making the reflection code too complex. This gives you the same result with much less overhead, but as mentioned in phoog

, you cannot compile code that won't compile.

[TestMethod]
public void NoPrivateConstructors()
{
    Assert.IsFalse(typeof(Logger).GetConstructors(/* binding flags... */).Any());
}

      

0


source







All Articles