Using a custom FXCop rule, I want to ensure that a method is called at the top of each unit test and that all unit test code is part of an Action passed into that method. Essentially I want this:
[TestMethod]
public void SomeTest()
{
Run(() => {
// ALL unit test code has to be inside a Run call
});
}
It's not hard to ensure that Run is indeed called:
public override void VisitMethod(Method member)
{
var method = member as Method;
if (method == null || method.Attributes == null)
return;
if (method.Attributes.Any(attr => attr.Type.Name.Name == "TestMethodAttribute") &&
method.Instructions != null)
{
if (!method.Instructions.Any(i => i.OpCode == OpCode.Call || i.Value.ToString() == "MyNamespace.Run"))
{
this.Problems.Add(new Problem(this.GetResolution(), method.GetUnmangledNameWithoutTypeParameters()));
}
base.VisitMethod(method);
}
The trick is to ensure there isn't something at the top of the test that is called BEFORE the Run statement. I've spent the past few hours hacking at the Instructions collection for patterns and trying to understand how to use the Body.Statements collection in code effectively.
This could also be posed as a simple IL question. I want to know a specific pattern I can validate that will accept this:
public void SomeTest()
{
Run(() => {
// Potentially lots of code
});
}
But will reject either of these:
public void SomeTest()
{
String blah = “no code allowed before Run”;
Run(() => {
// Potentially lots of code
});
}
public void SomeTest()
{
Run(() => {
// Potentially lots of code
});
String blah = “no code allowed after Run”;
}