Testing our Comment Analyzer
In previous posts we covered the basics of creating a comment analyzer and creating a code fix for that analyzer. The final thing that is needed for any analyzer is a good set of unit tests.
To start we need to create a TestClass
that inherits from CodeFixVerifier
.
[TestClass]
public class EmptyCommentCodeFix : CodeFixVerifier
{
}
The CodeFixVerifier
base class provides a few helper methods that make testing your analyzer much easier. To start using it we need to override a few methods. We'll start by overriding theGetCSharpCodeFixProvider
and return an instance of ourEmptyCommentCodeFix
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new AnalyzerSamples.Comments.EmptyCommentCodeFix();
}
Next we will override the GetCharpDiagnosticAnalyzer
method and return to it an instance of our EmptyCommentAnalyzer
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new EmptyCommentAnalyzer();
}
These two overrides provide the underlying base class with the instances it needs to work with all of the helper methods it provides. Obviously, you could do all of this wiring up yourself, but this base class just makes it easier.
At this point, we can write our first test. We'll start with a very simple test that exercises the most basic of uses of the diagnostic. We can start this by creating some basic test code:
[TestMethod]
public void TestBasicEmptyComment()
{
var testCode = @"
class Foo
{
public void Bar()
{
//
}
}";
Given this code, we expect a diagnostic to appear at line 6 column 9. We now need to declare what we expect to happen and verify it. To do this we can create a diagnostic result and use the VerifyCSharpDiagnostic
method.
var expected = new DiagnosticResult
{
Id = EmptyCommentAnalyzer.DiagnosticId,
Message = EmptyCommentAnalyzer.MessageFormat.ToString(),
Severity = DiagnosticSeverity.Warning,
Locations =
new[] {
new DiagnosticResultLocation("Test0.cs", 6, 9)
}
};
this.VerifyCSharpDiagnostic(testCode, expected);
This code will pass and verify that the diagnostic is raised at the correct location. Try playing with the line or column numbers. Notice that if you get them wrong, the error message will give you the correct location to make it easier to get your locations correct when first creating the unit tests. For example, if I change the column parameter to 10, then I get the following error:
Assert.IsTrue failed. Expected diagnostic to start at column "10" was actually at column "9"
At this point we can create the expected code for the fix and verify that the code gets fixed correctly. To do this, we use the VerifyCSharpFix
method sending it the original code and the fixed code.
var expectedFixedCode = @"
class Foo
{
public void Bar()
{
}
}";
this.VerifyCSharpFix(testCode, expectedFixedCode);
With that, we have a test that validates our analyzer and our code fix. The full code for the test class is:
[TestClass]
public class EmptyCommentCodeFix : CodeFixVerifier
{
[TestMethod]
public void TestBasicEmptyComment()
{
var testCode = @"
class Foo
{
public void Bar()
{
//
}
}";
var expected = new DiagnosticResult
{
Id = EmptyCommentAnalyzer.DiagnosticId,
Message = EmptyCommentAnalyzer.MessageFormat.ToString(),
Severity = DiagnosticSeverity.Warning,
Locations =
new[] {
new DiagnosticResultLocation("Test0.cs", 6, 9)
}
};
this.VerifyCSharpDiagnostic(testCode, expected);
var expectedFixedCode = @"
class Foo
{
public void Bar()
{
}
}";
this.VerifyCSharpFix(testCode, expectedFixedCode);
}
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new AnalyzerSamples.Comments.EmptyCommentCodeFix();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new EmptyCommentAnalyzer();
}
}
With all of the helper methods and classes provided by the Roslyn team, there is no excuse to not test your analyzers. For a more exhaustive lists of tests that could be run against this analyzer, you can look at the SA1120 unit tests in the StyleCopAnalyzers project on GitHub.