Native CodeRush test templates. Testing the order of method calls
In our work we have to write a lot of tests. To do this quickly, we use CodeRush templates . In this article, we will tell you how to create custom templates for testing. As an example, take the following task: to test the correct order of calls to protected class methods. We will use only NUnit without the use of libraries such as NMock and the like.
So, let's start with the experimental object. We will write a simple class containing several methods and having a specific order of their calls.
In Dunn class check that the resulting calling DoAction guaranteed to be executed methods BeforeAction , DoActionCore and AfterAction in the correct sequence and the desired number of times.
Testing will be based on writing the descendant of the SimpleClass class , which when calling a certain method will record that this method was called. For simplicity, we take a regular string as a trace object and append the name of the called method there. In the test, we will verify the resulting string with the expected result.
Define a naming convention for classes such as TestClass_Name. This will simplify the writing of a template for tests.
Briefly about CodeRush templates : they allow you to quickly insert frequently used code fragments in the editor, following certain rules for name substitution, formatting, etc. They are akin to code-snippets, but differ from them in their greater intelligence, providing a number of advantages, such as application contexts, the ability to analyze existing code, the presence of commands, line providers, fields, links and more.
Now we begin to write our own template for the heir to the class containing the trace string. Open the settings window, go to the Editor -> Templates group, the group of options for NUnit. Note that CodeRush already contains a predefined set of templates for writing NUnit tests, but we need to create another one.
Fig. 1 - Creating a new template for NUnit
Give the template a short name, for example, stu (from stub-class) and write the body of the template. We will design the template in such a way that when it is activated, the name of the source class will be stored in the clipboard and after pasting, a code will be created that reflects the rules defined above for names.
Fig. 2 - Writing the body of a template using predefined commands.
When writing a template, we use a predefined set of commands, selecting them from the list. Such teams here are “Paste” and “Caret”.
Now it’s important to indicate where this template can run. To do this, configure the Use usage parameters by setting the necessary values. Specify the Line.OnEmptyLine parameter for it.
Fig. 3 - Specifying the areas of use of the template
Similar to the first, we write the atr (add trace) template to add a trace string to the method.
In this case, the name of the current method will be automatically inserted when the template is activated and there is no need to first copy it to the clipboard. Let us define such areas of use of the template as InClass, InMethod
Fig. 4 - Template for inserting trace-line.
Templates are ready. It should be said that you can export templates, including self-created ones, to an xml file. And, if necessary, reuse them by importing from a previously created file, which avoids re-entering manually.
How does it all work? Let's try to write a test for SimpleClass.
We need a successor class for tests. Copy the name SimpleClass to the clipboard and type stu. A template for the inherited class containing the Trace property is inserted at the cursor location.
Fig. 5 - Activating the template and inserting the code
Now we will add trace information for each method that interests us. To do this, we will redo these methods. In Visual Studio, type “over” for this, then press the space bar and select the desired method names from the drop-down list, while thanking IntelliSense for not having to painfully recall their names. As a result, all the necessary methods are overridden and so far they simply call the base ones.
Now it's time to include our atr template. Let's go through these methods, activate the template for inserting a trace string. As a result, we get methods that will add their name to the Trace property after the call.
In addition to the name, any other information related to the call can be added to the trace object, for example, call parameters, etc.
Let us return directly to the test. Create a TextFixture for the test group of our class. By the way, to speed up its creation, you can also write your own template, which will include methods for SetUp and TearDown. We declare an instance of our descendant class, initialize it and write a test for the DoAction method . The test will consist in comparing the Trace property of the successor class after calling the method with the expected result, which reflects the correct sequence of calls to the protected methods of the class.
Run the test. The result is achieved - we made sure that everything inside the class works as it should.
In conclusion, I want to say that one of the minuses of the approach that uses trace-lines is that when you change the code of the source classes and the order of calls in them, you will have to modify the tests, or rather, the standard lines. Therefore, everything is good in moderation, and you yourself decide where and when to apply such a practice.
Good luck creating convenient test patterns!
Object to test
So, let's start with the experimental object. We will write a simple class containing several methods and having a specific order of their calls.
public class SimpleClass {
public void DoAction() {
BeforeAction();
try {
DoActionCore();
}
finally {
AfterAction();
}
}
protected virtual void BeforeAction() { }
protected virtual void AfterAction() { }
protected virtual void DoActionCore() { }
}
In Dunn class check that the resulting calling DoAction guaranteed to be executed methods BeforeAction , DoActionCore and AfterAction in the correct sequence and the desired number of times.
Testing will be based on writing the descendant of the SimpleClass class , which when calling a certain method will record that this method was called. For simplicity, we take a regular string as a trace object and append the name of the called method there. In the test, we will verify the resulting string with the expected result.
Define a naming convention for classes such as TestClass_Name. This will simplify the writing of a template for tests.
Template customization
Briefly about CodeRush templates : they allow you to quickly insert frequently used code fragments in the editor, following certain rules for name substitution, formatting, etc. They are akin to code-snippets, but differ from them in their greater intelligence, providing a number of advantages, such as application contexts, the ability to analyze existing code, the presence of commands, line providers, fields, links and more.
Now we begin to write our own template for the heir to the class containing the trace string. Open the settings window, go to the Editor -> Templates group, the group of options for NUnit. Note that CodeRush already contains a predefined set of templates for writing NUnit tests, but we need to create another one.
Fig. 1 - Creating a new template for NUnit
Give the template a short name, for example, stu (from stub-class) and write the body of the template. We will design the template in such a way that when it is activated, the name of the source class will be stored in the clipboard and after pasting, a code will be created that reflects the rules defined above for names.
#region Test«Paste» (stub class)
public class Test«Paste» :«Paste» {
string trace = string.Empty;
public Test«Paste»(«Caret») : base() {
}
public string Trace { get { return trace; } set { trace = value; } }
}
#endregion
Fig. 2 - Writing the body of a template using predefined commands.
When writing a template, we use a predefined set of commands, selecting them from the list. Such teams here are “Paste” and “Caret”.
Now it’s important to indicate where this template can run. To do this, configure the Use usage parameters by setting the necessary values. Specify the Line.OnEmptyLine parameter for it.
Fig. 3 - Specifying the areas of use of the template
Similar to the first, we write the atr (add trace) template to add a trace string to the method.
trace += "->«Member»";
«Caret»
In this case, the name of the current method will be automatically inserted when the template is activated and there is no need to first copy it to the clipboard. Let us define such areas of use of the template as InClass, InMethod
Fig. 4 - Template for inserting trace-line.
Templates are ready. It should be said that you can export templates, including self-created ones, to an xml file. And, if necessary, reuse them by importing from a previously created file, which avoids re-entering manually.
We write tests quickly
How does it all work? Let's try to write a test for SimpleClass.
We need a successor class for tests. Copy the name SimpleClass to the clipboard and type stu. A template for the inherited class containing the Trace property is inserted at the cursor location.
Fig. 5 - Activating the template and inserting the code
Now we will add trace information for each method that interests us. To do this, we will redo these methods. In Visual Studio, type “over” for this, then press the space bar and select the desired method names from the drop-down list, while thanking IntelliSense for not having to painfully recall their names. As a result, all the necessary methods are overridden and so far they simply call the base ones.
Now it's time to include our atr template. Let's go through these methods, activate the template for inserting a trace string. As a result, we get methods that will add their name to the Trace property after the call.
#region TestSimpleClass (stub class)
public class TestSimpleClass : SimpleClass {
string trace = string.Empty;
public TestSimpleClass()
: base() {
}
public string Trace { get { return trace; } set { trace = value; } }
protected override void BeforeAction() {
base.BeforeAction();
trace += "->BeforeAction";
}
protected override void AfterAction() {
base.AfterAction();
trace += "->AfterAction";
}
protected override void DoActionCore() {
base.DoActionCore();
trace += "->DoActionCore";
}
}
#endregion
In addition to the name, any other information related to the call can be added to the trace object, for example, call parameters, etc.
Let us return directly to the test. Create a TextFixture for the test group of our class. By the way, to speed up its creation, you can also write your own template, which will include methods for SetUp and TearDown. We declare an instance of our descendant class, initialize it and write a test for the DoAction method . The test will consist in comparing the Trace property of the successor class after calling the method with the expected result, which reflects the correct sequence of calls to the protected methods of the class.
#region SimpleClassTests
[TestFixture]
public class SimpleClassTests {
TestSimpleClass testClass;
[SetUp]
public void Setup() {
testClass = new TestSimpleClass();
}
[TearDown]
public void Teardown() {
testClass = null;
}
[Test]
public void DoActionMethod() {
testClass.Trace = string.Empty;
testClass.DoAction();
string expectedTrace = "->BeforeAction->DoActionCore->AfterAction";
Assert.AreEqual(expectedTrace, testClass.Trace);
}
}
#endregion
Run the test. The result is achieved - we made sure that everything inside the class works as it should.
In conclusion, I want to say that one of the minuses of the approach that uses trace-lines is that when you change the code of the source classes and the order of calls in them, you will have to modify the tests, or rather, the standard lines. Therefore, everything is good in moderation, and you yourself decide where and when to apply such a practice.
Good luck creating convenient test patterns!