{"id":355,"date":"2008-03-14T00:00:00","date_gmt":"2008-03-14T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/testing-times-ahead-extending-nunit\/"},"modified":"2021-05-11T15:56:44","modified_gmt":"2021-05-11T15:56:44","slug":"testing-times-ahead-extending-nunit","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/testing-times-ahead-extending-nunit\/","title":{"rendered":"Testing Times Ahead: Extending NUnit"},"content":{"rendered":"<div id=\"word\">\n<p class=\"MsoNormal\"><b>Extending NUnit 2.4<\/b><\/p>\n<p class=\"MsoNormal\">This article discusses why you might want to extend NUnit with custom addins and attributes, and how to go about doing it.&#160; NUnit has become the de-facto standard unit-testing framework for the .Net platform.&#160; Originally a port of JUnit, it has now grown, and has been completely re-written to take advantage of the .Net framework.&#160;&#160; This article is based on NUnit 2.4.6. <\/p>\n<p class=\"MsoNormal\">The sample source code for this article can be downloaded <a href=\"http:\/\/www.simple-talk.com\/content\/file.ashx?file=777\">here<\/a>.<\/p>\n<p class=\"MsoNormal\"><b>Why Extend?<\/b><\/p>\n<p class=\"MsoNormal\">Why would you need to extend NUnit?&#160; NUnit provides an excellent harness for unit testing, but you will have requirements which cannot be solved using the framework.&#160; <\/p>\n<p class=\"MsoNormal\">By extending NUnit, you can move this generic repeatable code from your test code into an attribute that can then be added to your test methods.&#160;&#160; <\/p>\n<p class=\"MsoNormal\">This has a number of advantages:<\/p>\n<ul>\n<li class=\"MsoNormal\">Your tests are more readable because an attribute can describe more about the test than some code in a setup method,  <\/li>\n<li class=\"MsoNormal\">You can reuse your extensions instead of them being isolated in test code.&#160;&#160;  <\/li>\n<li class=\"MsoNormal\">You can also extend the code to allow additional possibilities not possible out of the box, such as dynamically creating your tests and test data. <\/li>\n<\/ul>\n<p class=\"MsoNormal\"><b>NUnit Extension Points<\/b><\/p>\n<p class=\"MsoNormal\">NUnit 2.4 has a set of extension points that allow you to hook into the framework at various different levels to solve different problems.&#160; <\/p>\n<p class=\"MsoNormal\">These are the different types of extension points that are available. <\/p>\n<p class=\"ListParagraphCxSpFirst\">1)&#160;&#160;&#160;&#160;&#160; Suite Builders<\/p>\n<p class=\"ListParagraphCxSpMiddle\">This is arguable the most flexible and highest level hook into NUnit. The Suite Builder extension point allows you to implement your own version of <b>TestFixture<\/b>.&#160; This means you can redefine much of the way that NUnit finds, and executes the tests.&#160; For example, if you need a different way to identify tests, instead using the <b>[Test]<\/b> attribute, you could create your own Suite Builder and, by using Reflection on the type, you could dynamically add methods as tests.<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"ListParagraphCxSpMiddle\">Another advantage of this is that you can define the way to execute the <b>Test<\/b> Method.&#160; Every test is defined as a <b>Test<\/b> object, these <b>Test<\/b> objects define the tests name, how the test should be executed, the arguments for a test, any expected exceptions and other information NUnit uses internally.&#160; By dynamically creating your test fixture, you can alter the behaviour of any of the tests.&#160; <\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"ListParagraphCxSpMiddle\">2)&#160;&#160;&#160;&#160;&#160; Test Case Builders<\/p>\n<p class=\"ListParagraphCxSpMiddle\">Where Suite builders work by redefining the <b>TestFixture<\/b>, Test Case Builders redefine how the Test attribute behaves.&#160; By using the Test Case Builder to hook into NUnit, you can define a custom test within a standard <b>NUnitTestFixture<\/b>.&#160; <\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"ListParagraphCxSpMiddle\">These custom tests work by dynamically creating the test objects and adding them to an existing Test Fixture to execute.&#160; This allows you to dynamically build the tests to execute within your test fixture based on data that might not be known until run time, for example the contents of a directory or database. <\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"ListParagraphCxSpMiddle\">3)&#160;&#160;&#160;&#160;&#160; Test Decorators<\/p>\n<p class=\"ListParagraphCxSpMiddle\">Test decorators are combined with an existing <b>[Test]<\/b> attribute in order to add additional behaviour to a test when it is executed, such as modifying the description of the test or executing a command before the test is started.&#160; Unlike the two previous tests, we still use NUnit&#8217;s basic features but tweak the actual execution. <\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"ListParagraphCxSpMiddle\">An example of this is being able to add a <b>RepeatAttribute<\/b> to a test which causes the test to execute a certain number of times instead of just once. <\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#160;<\/p>\n<p class=\"ListParagraphCxSpMiddle\">4)&#160;&#160;&#160;&#160;&#160; Event Listeners<\/p>\n<p class=\"ListParagraphCxSpMiddle\">The fourth main way to extend NUnit is to listen to the various events Nunit fires during execution of the test suite.&#160; The events you can hook into are:<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Run Started<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Run Finished<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Test Started<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Test Finished<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Suite Started<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Suite Finished<\/p>\n<p class=\"ListParagraphCxSpMiddle\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Unhandled Exception<\/p>\n<p class=\"ListParagraphCxSpLast\">&#194;&#183;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Test Output<\/p>\n<p class=\"MsoNormal\">By listening to these events, you can add a response as required.&#160; A common requirement for this would be to provide additional\/different reporting functionality of test execution.<\/p>\n<p class=\"ListParagraph\">Note: Version 2.4.6 has a known bug with event listeners that cause the loading of the addin to fail.<\/p>\n<p class=\"MsoNormal\"><b>How to Extend NUnit?<\/b><\/p>\n<p class=\"MsoNormal\">So how would you actually go about implementing the addins?<\/p>\n<p class=\"MsoNormal\"><b>Hello World<\/b><\/p>\n<p class=\"MsoNormal\">To start with, I am going to create a Hello World attribute.&#160; NUnit addins can be created as any .Net assembly as long as they reference the correct NUnit assemblies and implement the interfaces correctly.&#160; <\/p>\n<p class=\"MsoNormal\">To get started, you will need to create a class library (I will be using C#), you will then need to reference the correct NUnit assemblies, which can be found in the nunit directory, which are <b>nunit.framework.dll<\/b>, <b>nunit.core.dll<\/b> and <b>nunit.core.interfaces.dll<\/b>.&#160; With those in place, we can create our first addin. <\/p>\n<p class=\"MsoNormal\">The type of extension point and addin you wish to create will depend on how the addin gets implemented.&#160; For this example, I will create a Test Case Builder addin that will take a test object and add a description before passing it back to NUnit to execute.&#160; The Test Case Builder requires an object to implement the NUnit.Core.Extensibility.ITestCaseBuilder interface.<\/p>\n<p class=\"MsoNormal\">The interface has two method, one called<b> CanBuildFrom<\/b> which returns true if the current test method is supported by the attribute and false if it isn&#8217;t.&#160; The second method is called <b>BuildFrom<\/b> that takes the current method as a <b>MethodInfo<\/b> object and returns a constructed Test object to execute. Figure 1 demonstrates the code required to implement the addin.&#160; The <b>CanBuildFrom<\/b> just checks to make sure it has the correct attribute (see below), the <b>BuildFrom<\/b> method then simply creates the built-in <b>NUnitTestMethod<\/b> object based on the current method, then sets the description property and finally returns it to the calling code (NUnit).<\/p>\n<table class=\"MsoNormalTable\" id=\"table1\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">#region ITestCaseBuilder Members<\/p>\n<p class=\"MsoNormal\">public bool CanBuildFrom(System.Reflection.MethodInfo method)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return NUnit.Core.Reflect.HasAttribute(method, &#8220;NUnitAddInAttributes.HelloWorldAttribute&#8221;, false);<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\">public NUnit.Core.Test BuildFrom(System.Reflection.MethodInfo method)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; NUnitTestMethod tmethod = new NUnitTestMethod(method);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; tmethod.Description = &#8220;Hello World Test Addin Method&#8221;;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return tmethod;<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\">#endregion<\/p>\n<p class=\"MsoNormal\"><span class=\"caption\"><br \/>Figure 1: &#8211; ITestCaseBuilder code<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">The next stage is to create the correct attribute so it can be used by the test code.&#160; The first time I attempted this, I put the attributes into the same assembly as the addins.&#160; However, this meant that my test code also had to reference <b>nunit.core<\/b> and <b>nunit.core.interfaces<\/b> if it wanted to use my attribute: this is not great for &#8216;zero fiction&#8217; usage, so I moved my attribute code into a separate assembly that my test code could then reference in order to use my addin.&#160; This had the benefit that they don&#8217;t need to reference any additional assemblies. <\/p>\n<p class=\"MsoNormal\">As the attribute is used to tell NUnit to use the addin instead of NUnit&#8217;s Test attribute, the attribute itself is simple as shown in figure 1.<\/p>\n<table class=\"MsoNormalTable\" id=\"table2\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">namespace NUnitAddInAttributes<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public class HelloWorldAttribute : Attribute<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 2: &#8211; Hello World Attribute<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Now we have a useable <b>addin<\/b>, we need to tell NUnit about it.&#160; The first step is to add a <b>NUnitAddinAttribute<\/b> to the <b>addin<\/b> class so that NUnit can find it.<\/p>\n<table class=\"MsoNormalTable\" id=\"table3\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[NUnitAddin(Description = &#8220;Hello World Plugin&#8221;)]<\/p>\n<p class=\"MsoNormal\">public class HelloWorld : NUnit.Core.Extensibility.IAddin, ITestCaseBuilder<br \/><span class=\"caption\"><br \/>Figure 3: &#8211; NUnitAddinAttribute<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">The next step is to install it into the correct extension point.&#160; The <b>IAddin<\/b> interface has a single method called <b>Install<\/b>; this has a <b>IExtensionHost<\/b> parameter that we can use to gain access to the different extension points.&#160; By calling the method <b>GetExtensionPoint<\/b> and passing in the name of the extension we get a <b>IExtensionPoint<\/b> object.&#160; We can then call the Install method on this object, passing in the object that implements the correct interface, finally returning true to say it completed successfully.<\/p>\n<p class=\"MsoNormal\">Figure 4 is the code for installing a Test Case Builder addin. <\/p>\n<table class=\"MsoNormalTable\" id=\"table4\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">#region IAddin Members<br \/>public bool Install(NUnit.Core.Extensibility.IExtensionHost host)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; IExtensionPoint testCaseBuilders = host.GetExtensionPoint(&#8220;TestCaseBuilders&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; testCaseBuilders.Install(this); \/\/this implments both interfaces<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return true;<\/p>\n<p class=\"MsoNormal\">}<br \/>#endregion<\/p>\n<p class=\"MsoNormal\"><span class=\"caption\"><b><br \/>Figure 4: &#8211; Addin Install<\/b><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">If we load NUnit and go Tools &gt; Addins the following dialog box will appear. <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/484-image002.jpg\" alt=\"484-image002.jpg\" \/><\/p>\n<p class=\"MsoNormal\">You should see the addin successfully listed, together with a <b>RepeatedTestDecorator<\/b>, which is included within NUnit. <\/p>\n<p class=\"MsoNormal\">Figure 5 is an example of how to use the attribute with your test.&#160; Remember, a Test Case Builder <b>addin<\/b> attribute is used instead of the <b>[Test]<\/b> attribute which you would normally expect, so if we use the attribute there is no need to redefine it. <\/p>\n<table class=\"MsoNormalTable\" id=\"table5\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[HelloWorld]<\/p>\n<p class=\"MsoNormal\">public void Test()<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Assert.IsTrue(true);<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 5: &#8211; Usage Example<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Within the NUnit GUI, in the properties dialog for the test, we can see that the description has successfully been set via the addin. <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/484-image004.jpg\" alt=\"484-image004.jpg\" \/><\/p>\n<p class=\"MsoNormal\">This is a very simple example, but shows how to create the Addin. Now for more detail.<\/p>\n<p class=\"MsoNormal\"><b>Suite Builders<\/b><\/p>\n<p class=\"MsoNormal\">As discussed above, the suite builder allows you to redefine how the tests are found and executed. <b>Addins<\/b> that extend this will require the <b>ISuiteBuilder<\/b> interface.&#160; This is similar to the <b>ITestCaseBuilder<\/b> interface, and has two methods &#8211; <b>CanBuildFrom<\/b> and <b>BuildFrom<\/b>.&#160; However, instead of <b>BuildFrom<\/b> returning a single test, it returns a complete test suite with all the tests added.&#160; The NUnit object model is slightly confusing where a <b>TestSuite<\/b> is actually a type of Test, which is why <b>BuildFrom<\/b> can return either single tests or a suite of tests. <\/p>\n<table class=\"MsoNormalTable\" id=\"table6\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public bool CanBuildFrom(Type type)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return Reflect.HasAttribute(type, &#8220;NUnitAddinAttributes.SuiteBuilderAttribute&#8221;, false);<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\">public Test BuildFrom(Type type)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return new SuiteTestBuilder(type);<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\"><span class=\"caption\"><br \/>Figure 6:- ISuiteBuilder code<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">With <b>BuildFrom<\/b> returning a <b>TestSuite<\/b> object, we need to implement the object and add any tests required.&#160; Figure 7 is the code for my custom Test Suite.&#160; Within the constructor, I use reflection to get a list of all the methods within the Type, which is the class containing all of the methods.&#160; If the method name starts with MyTest, I add it to the <b>TestSuite<\/b> as a standard <b>NUnitTestMethod<\/b>, at this point I could also have redefined how each test is executed, I will discuss this in more detail in the next section. <\/p>\n<table class=\"MsoNormalTable\" id=\"table7\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public class SuiteTestBuilder : TestSuite<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public SuiteTestBuilder(Type fixtureType): base(fixtureType)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.Fixture = Reflect.Construct(fixtureType);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach (MethodInfo method in fixtureType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (method.Name.StartsWith(&#8220;MyTest&#8221;))<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.Add(new NUnitTestMethod(method));<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 7: &#8211; Suite Test Builder code<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">With our <b>TestSuite<\/b> code completed, we need to install the addin.&#160; To install the addin, we need to access the extension point called &#8220;SuiteBuilders&#8221; and pass in the <b>ISuiteBuilder<\/b> object as shown in figure 8.&#160; We also need to add the <b>NUnitAddinAttribute<\/b> to the class. <\/p>\n<table class=\"MsoNormalTable\" id=\"table8\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public bool Install(IExtensionHost host)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; IExtensionPoint builders = host.GetExtensionPoint(&#8220;SuiteBuilders&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; if (builders == null)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; return false;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; builders.Install(this);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return true;<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\"><span class=\"caption\"><span class=\"caption\"><br \/>Figure 8: &#8211; Suite Builder Install<\/span><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Finally, we need to implement an attribute for use within our tests, this is identify which classes should use the addin.<\/p>\n<table class=\"MsoNormalTable\" id=\"table9\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]<\/p>\n<p class=\"MsoNormal\">public class SuiteBuilderAttribute : Attribute<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 9: &#8211; Suite Builder Attribute<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Figure 10 is an example of how to use the addin.&#160; There is no reference to <b>TestFixture<\/b> or <b>Test<\/b> attributes, as we would expect. All we need to do is add the <b>SuiteBuilderAttribute<\/b> to the top of the class, then prefix any tests we want to be executed with &#8216;MyTest&#8217;, which is what the addin uses to identity the methods. <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[SuiteBuilder]<\/p>\n<p class=\"MsoNormal\">public class SampleSuiteExtensionTests<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public void MyTest1()<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(&#8220;Hello from test 1&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public void MyTest2()<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(&#8220;Hello from test 2&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public void NotATest()<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(&#8220;This is not a test and so shouldn&#8217;t be called.&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\"><span class=\"caption\"><br \/>Figure 10:- Usage Sample<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">The NUnit GUI should now show that we have two tests listed for that object which can be executed as normal.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/484-image006.jpg\" alt=\"484-image006.jpg\" \/><\/p>\n<p class=\"MsoNormal\">This is a very powerful extension, but with limited usage. Test Case Builders and Test Decorates have much more of an impact. <\/p>\n<p class=\"MsoNormal\"><b>Test Case Builders<\/b><\/p>\n<p class=\"MsoNormal\">Test Case Builders allow you to extend NUnit without having to rewrite large parts of the fundamental framework.&#160; By using Test Case Builders, we can take a single method with the correct attribute and define one or more different tests that can be executed as part of the test suite.&#160;&#160; This allows much more flexibility with NUnit, thereby improving the readability and maintenance of tests.&#160; This is because the process of defining the tests to be executed can be customized via the attribute.&#160; The example I will use to demonstrate this extension is the ability to define a test case for each row from a SQL statement, the columns of which are then passed into the test as parameters to use as part of the test. Figure 11 demonstrates the final extension being used. <\/p>\n<p class=\"MsoNormal\">Instead of defining the <b>[Test]<\/b> attribute, we define a <b>SqlServerDataSource<\/b> attribute, and set the connection string and query parameters. When NUnit loads the test, it will execute the query and create a separate test for each row returned from the query. <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[SqlServerDataSource(ConnectionString = &#8220;Data Source=.;Initial Catalog=Northwind;Integrated Security=True&#8221;, Query = &#8220;SELECT CustomerID FROM Northwind.dbo.Customers&#8221;)]<\/p>\n<p class=\"MsoNormal\">public void TestCustomerIDIsValid(string customerID)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Console.WriteLine(customerID);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Assert.IsFalse(string.IsNullOrEmpty(customerID));<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 11: &#8211; Sample Usage<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">When the tests are executed, it will pass in the values (one parameter for each column returned) so we can use them to test against.&#160; This is useful for dynamically creating the tests, especially if you do not know all the possible test values when you are creating your tests. By using this attribute, anyone can include additional test cases for the method. <\/p>\n<p class=\"MsoNormal\">We have already created a Test Case Builder before in the Hello World example so I won&#8217;t go into the concept here.&#160; Once we have inherited from the <b>ITestCaseBuilder<\/b> interface, we need to determine if tests can built from the method. <\/p>\n<p class=\"MsoNormal\">The major different is that our attribute now has properties which we can use to pass data into our attribute.&#160; Within our attribute code, we simply add the properties we want.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]<\/p>\n<p class=\"MsoNormal\">public class SqlServerDataSourceAttribute : Attribute<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public string ConnectionString { get; set; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; public string Query { get; set; }<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 12: &#8211; Sql Server Data Source Attribute<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Figure 13 defines if the test method is supported by the <b>SqlDataSource<\/b> Addin we are creating.&#160; The first task is to see if the current method has a <b>SqlServerDataSourceAttribute<\/b>, this is done using the Reflect class which is a wrapper around <b>System.Reflection<\/b> and provides an interface that is easy to understand &#8211; this can be found in <b>NUnit.Core<\/b>. &#160;If the method does not have the attribute then it is not supported so we return false.&#160; Otherwise, we access the attribute using Reflect, and check to make sure the conversion works correctly and return true to indicate it is a supported method.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public bool CanBuildFrom(MethodInfo method)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; if (method == null)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new ArgumentNullException(&#8220;method&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; if (Reflect.HasAttribute(method, SqlServerAttribute, false))<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; SqlServerDataSourceAttribute sql = Reflect.GetAttribute(method, SqlServerAttribute, false) as SqlServerDataSourceAttribute;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (sql != null)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return true;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return false;<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 13: &#8211; Sql Server Can Build From method<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Once NUnit knows that it should use the Addin we need to define how it can actually build a test, or in this case a collection of tests.&#160; Figure 14 shows the code for defining how to build the test suite.&#160; The first task is to gain access to the attribute again, enabling us to access the connection string and query provided by the user.&#160; We then need to define a standard TestSuite which is passed to the <b>CreateRowsFromSQL<\/b> method along with the method and the attribute (Figure 14), finally returning the populated suite back to NUnit.&#160; <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public Test BuildFrom(MethodInfo method)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; if (method == null)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new ArgumentNullException(&#8220;method&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; SqlServerDataSourceAttribute sql = Reflect.GetAttribute(method, SqlServerAttribute, false) as SqlServerDataSourceAttribute;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; string parentName = method.DeclaringType.ToString();<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; TestSuite suite = new TestSuite(parentName, method.Name);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; CreateRowsFromSQL(method, suite, sql);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return suite;<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 14: &#8211; Sql Server Build From code<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Within <b>CreateRowsFromSQL<\/b> we create all of the tests to be executed and add them to the suite.&#160; I am just using standard ADO.net to query the database based on the attribute&#8217;s properties.&#160; Once I have queried the database, I iterate each field and use it to help create a test name which allows the test to be identified when executing.&#160; Finally, I create a <b>SqlServerTestMethod<\/b> object that defines how the test is executed.&#160; To setup the object; I pass in the test method, the name of the test and then the rows returned from the query as an object array for use during execution. I then add the created <b>SqlServerTestMethod<\/b> into the test suite for execution. <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">sqlConn = new SqlConnection(sql.ConnectionString);<\/p>\n<p class=\"MsoNormal\">sqlConn.Open();<\/p>\n<p class=\"MsoNormal\">SqlCommand sqlCmd = new SqlCommand(sql.Query, sqlConn);<\/p>\n<p class=\"MsoNormal\">SqlDataReader sdr = sqlCmd.ExecuteReader();<\/p>\n<p class=\"MsoNormal\">int fieldCount = sdr.FieldCount;<\/p>\n<p class=\"MsoNormal\">while (sdr.Read())<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; try<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; object[] args = new object[fieldCount];<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; string methodName = &#8220;&#8221;;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; for (int i = 0; i &lt; fieldCount; i++)&#160; \/\/Create test name<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; object v = sdr.GetValue(i);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (string.IsNullOrEmpty(methodName))<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; methodName = v.ToString().Replace(&#8221; &#8220;, &#8220;&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; methodName = methodName + &#8220;,&#8221; + v.ToString().Replace(&#8221; &#8220;, &#8220;&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; args[i] = v; \/\/Populate collection<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; suite.Add(new SqlServerTestMethod(method, method.Name + &#8220;(&#8221; + methodName + &#8220;)&#8221;, args));<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; catch (Exception ex)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; NUnitTestMethod ts = new NUnitTestMethod(method);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; ts.RunState = RunState.NotRunnable;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; ts.IgnoreReason = string.Format(<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#8220;Exception thrown.&#160; Check query and connection strings are correctly for {0}.&#160; Exception {1}&#8221;, method.Name, ex.Message);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; suite.Add(ts);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 15: &#8211; Snippet from CreateRowsFromSQL<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">If an error occurs during the setup we need to alert the user someone.&#160; One approach is use the catch block create another test, set the running state to be Not Runnable and then set a reason, which is displayed to the user in the GUI.&#160; When the tests are executed, they will have a yellow icon and the message will appear under the Tests Not Run tab. <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/484-image008.jpg\" alt=\"484-image008.jpg\" \/><\/p>\n<p class=\"MsoNormal\">If it was more of a serious error that affects the entire test suite we could set the same properties directly on the test suite.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">suite.RunState = RunState.NotRunnable;<\/p>\n<p class=\"MsoNormal\">suite.IgnoreReason =<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; string.Format(<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#8220;SQL Exception thrown.&#160; Check query and connection strings are correctly for {0}.&#160; Exception {1}&#8221;, suite.TestName, ex.Message);<br \/><span class=\"caption\"><br \/>Figure 16: &#8211; Snippet from CreateRowsFromSQL error handling<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">This code will give us a test suite containing a number of tests based on rows of the query, if our SQL statement returned 10 rows of data then 10 tests would be created in the test suite. The next stage is to define how they can be executed. One approach would be to use the standard <b>NUnitTestMethod<\/b>, as we did in suite builder.&#160; This does not support parameters and so, as that is a major requirement, we need to create our own TestMethod object. <\/p>\n<p class=\"MsoNormal\">The first step is to inherit from <b>NUnitTestMethod<\/b>, which will give us the fundamental support for executing the test. We then need to define our own constructor so we can pass in the arguments to the object.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public SqlServerTestMethod(MethodInfo method, string testName, object[] arguments) : base(method)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; _arguments = arguments;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; TestName.Name = testName;<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 17: &#8211; Sql Server Test Method Constructor<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Within the constructor, I set the TestName property to be the test name we created based on the row.<\/p>\n<p class=\"MsoNormal\">The next step is to pass in the arguments to the test.&#160; To do this, we need to override the <b>RunTestMethod<\/b> that is called to execute the test.&#160; The first task is to ensure we have arguments, if not, then we need to pass in null. We thereby gain access to the current <b>TestSuite<\/b> in order to access the test fixture. &#160;Finally, we use Reflection to invoke the test method within the test fixture, passing in the arguments as a parameter. <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public override void RunTestMethod(TestCaseResult testResult)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; object[] arguments = _arguments ?? new object[] {null};<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; TestSuite testSuite = (TestSuite) this.Parent.Parent;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Reflect.InvokeMethod(this.Method, testSuite.Fixture, arguments); \/\/Execute Test<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 18: &#8211; Override Run Test Method<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Under the covers, the CLR will set the arguments and do any type conversion required, finally invoking the test just like NUnit does with the [Test] attribute. <\/p>\n<p class=\"MsoNormal\">In summary, by using the Test Case Builder extension, a single test method can be reused in several different ways to meet your own requirement for defining test values. <\/p>\n<p class=\"MsoNormal\"><b>Test Decorators<\/b><\/p>\n<p class=\"MsoNormal\">A test decorator allows us to make simple modifications to the test without having a great affect on the way that NUnit processes the test.&#160; Test Decorators allow us to add additional attributes to the standard [Test] that to either define the way the test is executed, set properties on the test such as description, or run commands before\/after the test has been executed.&#160; For this extension, I will create a decorate which can execute a SQL Statement before or after, or before and after the test is executed &#8211; great for creating and deleting test data. <\/p>\n<p class=\"MsoNormal\">Figure 19 is an example of how the test decorator could be used. The <b>TestSequence<\/b> enumeration simply indicates when to execute the query. <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[Test]<\/p>\n<p class=\"MsoNormal\">[ExecuteSql(ExecuteWhen = TestSequence.BeforeAndAfter, Connection = &#8220;Data Source=.;Initial Catalog=Northwind;Integrated Security=True&#8221;, Script = &#8220;DELETE FROM [Order Details]&#8221;)]<\/p>\n<p class=\"MsoNormal\">public void Test()<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Assert.IsTrue(true);<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 19: &#8211; Sample Usage<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">All test decorators must implement the <b>ITestDecorator<\/b> and install into the <b>TestDecorators<\/b> extension point.&#160; The <b>ITestDecorator<\/b> has a single method called <b>Decorate<\/b>. This has the parameters of the constructed Test object (built via the Test attribute) and the member info for the test method.&#160; This member info can be used to access all the metadata about the method, such as attributes. <\/p>\n<p class=\"MsoNormal\">&#160;Figure 20 is the Decorate method for the <b>ExecuteSQL<\/b> extension.&#160; The first task is to check that the test is actually a <b>NUnitTestMethod<\/b> (if you want to support other Test Case Builders then you will need to add checking for this) to ensure it is not a test suite.&#160; I then get the attributes for the method, and for each attribute of type <b>ExecuteSqlAttribute<\/b> I add it to the list.&#160; Once I have finished processing, I then create an <b>ExecuteSqlTestMethod<\/b> so I can configure how the test is executed , I also pass in the collection of <b>ExecuteSqlAttributes<\/b> as a parameter.&#160;&#160;&#160; The purpose of processing all the attributes as a list is to allow support for multiple execute sql attributes per test method, each of which could define a different query and test sequence. <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public Test Decorate(Test test, System.Reflection.MemberInfo member)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; if (test is NUnitTestMethod)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; List&lt;ExecuteSqlAttribute&gt; methodAttributes = new List&lt;ExecuteSqlAttribute&gt;();<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Attribute[] attributes = Reflect.GetAttributes(member, ExecuteSqlAttribute, false);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (methodAttributes.Count != attributes.Length)&#160; \/\/Already processed<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach (Attribute attr in attributes) \/\/Need to convert them all<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ExecuteSqlAttribute sqlAttribute = attr as ExecuteSqlAttribute;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (sqlAttribute != null &amp;&amp; !methodAttributes.Contains(sqlAttribute))<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; methodAttributes.Add(sqlAttribute);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; test = new ExecuteSqlTestMethod(((NUnitTestMethod) test).Method, methodAttributes);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return test;<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 20: &#8211; Test Decorator for Execute SQL<\/span> <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">The <b>ExecuteSqlTestMethod<\/b> inherits from <b>NUnitTestMethod<\/b>, in order to customise the Run method.&#160; Our run method executes any sql attributes marked as being &#8216;required to execute&#8217; <b>Before<\/b> or <b>BeforeAndAfter<\/b>, it then calls the Run method on the base object (<b>NUnitTestMethod<\/b>) thereby allowing all of the additional processing, such as error checking, to take place via NUnit.&#160; Finally it does another search for all the sql attributes which are marked <b>After<\/b> or <b>BeforeAndAfter<\/b>.&#160; If it finds an attribute it will call the <b>ExecuteSql<\/b> method (Figure 21).<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public override void Run(TestCaseResult testResult)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; try<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach (ExecuteSqlAttribute attribute in _sqlAttributes)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (attribute.ExecuteWhen == TestSequence.Before ||<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; attribute.ExecuteWhen == TestSequence.BeforeAndAfter)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ExecuteSql(attribute);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; base.Run(testResult);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach (ExecuteSqlAttribute attribute in _sqlAttributes)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (attribute.ExecuteWhen == TestSequence.After ||<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; attribute.ExecuteWhen == TestSequence.BeforeAndAfter)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ExecuteSql(attribute);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; catch (System.Data.SqlClient.SqlException ex)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; testResult.Failure(&#8220;SQL Exception Thrown from TempFileAttribute: &#8221; + ex.Message, ex.StackTrace);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 21: &#8211; Execute Sql Run Method<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">private void ExecuteSql(ExecuteSqlAttribute attribute)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; SqlConnection sqlConn = null;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; try<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; sqlConn = new SqlConnection(attribute.Connection);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; sqlConn.Open();<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; SqlCommand sqlCmd = new SqlCommand(attribute.Script, sqlConn);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; sqlCmd.ExecuteNonQuery();<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; finally<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; {<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (sqlConn != null &amp;&amp; sqlConn.State != ConnectionState.Closed)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; sqlConn.Close();<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; }<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 22: &#8211; Execute Sql ExecuteSql method<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">This decorator can then be used to execute sql commands during the execution of the test itself.&#160; This is great for defining SQL to be executed on a test-by-test basis.&#160; If the query execution fails then the test will fail, but with some correct <b>try&#8230;catch<\/b> blocks you can change this.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">[Test]<\/p>\n<p class=\"MsoNormal\">[ExecuteSql(ExecuteWhen = TestSequence.BeforeAndAfter, Connection = &#8220;Data Source=.;Initial Catalog=Northwind;Integrated Security=True&#8221;, Script = &#8220;DELETE FROM [Order Details]&#8221;)]<\/p>\n<p class=\"MsoNormal\">[ExecuteSql(ExecuteWhen = TestSequence.Before, Connection = &#8220;Data Source=.;Initial Catalog=Northwind;Integrated Security=True&#8221;, Script = &#8220;select &#8216;before'&#8221;)]<\/p>\n<p class=\"MsoNormal\">[ExecuteSql(ExecuteWhen = TestSequence.After, Connection = &#8220;Data Source=.;Initial Catalog=Northwind;Integrated Security=True&#8221;, Script = &#8220;select &#8216;after'&#8221;)]<\/p>\n<p class=\"MsoNormal\">public void Test()<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Assert.IsTrue(true);<\/p>\n<p class=\"MsoNormal\">}<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\"><b>&#160;<\/b><\/p>\n<p class=\"MsoNormal\"><b>Event Listeners<\/b><\/p>\n<p class=\"MsoNormal\">As mentioned earlier, event listeners are currently broken in 2.4.6; this should be fixed in later releases. <\/p>\n<p class=\"MsoNormal\">Event Listeners allow you to hook into various events that NUnit fires at various points in the test suite execution.&#160;&#160; This is great for providing additional reporting functionality, which is the example I will do so every event will write information out to the Debug listener. <\/p>\n<p class=\"MsoNormal\">In order to create an event listener addin, the class needs to inherit from the <b>EventListener<\/b> object. Figure 23 is a list of all the methods on the object where you can provide implementation hooks.&#160; Note that all the methods must be included in the addin; the actual method body can be empty if you do not wish to do anything with that event.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">#region EventListener Members<\/p>\n<p class=\"MsoNormal\">public void RunFinished(Exception exception);<\/p>\n<p class=\"MsoNormal\">public void RunFinished(TestResult result);<\/p>\n<p class=\"MsoNormal\">public void RunStarted(string name, int testCount);<\/p>\n<p class=\"MsoNormal\">public void SuiteFinished(TestSuiteResult result); <\/p>\n<p class=\"MsoNormal\">public void SuiteStarted(TestName testName); <\/p>\n<p class=\"MsoNormal\">public void TestFinished(TestCaseResult result);<\/p>\n<p class=\"MsoNormal\">public void TestOutput(TestOutput testOutput);<\/p>\n<p class=\"MsoNormal\">public void TestStarted(TestName testName);<\/p>\n<p class=\"MsoNormal\">public void UnhandledException(Exception exception);<\/p>\n<p class=\"MsoNormal\">#endregion<br \/><span class=\"caption\"><br \/>Figure 23: &#8211; Event Listener events<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">An example of how to implement the code for the different events is shown in figure 24.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public void RunStarted(string name, int testCount)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Debug.Write(&#8220;Test Started &#8221; + name + &#8221; &#8221; + testCount);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/p>\n<p class=\"MsoNormal\">}<\/p>\n<p class=\"MsoNormal\">public void RunFinished(TestResult result)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; Debug.Write(&#8220;Test Finished &#8221; + name + &#8221; &#8221; + result.ResultState);<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 24: &#8211; Event Listener implementation<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Finally, to install the addin we need to use the extension point named &#8220;EventListeners&#8221;.<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">public bool Install(IExtensionHost host)<\/p>\n<p class=\"MsoNormal\">{<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; IExtensionPoint listeners = host.GetExtensionPoint(&#8220;EventListeners&#8221;);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; if (listeners == null)<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; return false;<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; listeners.Install(this);<\/p>\n<p class=\"MsoNormal\">&#160;&#160;&#160; return true;<\/p>\n<p class=\"MsoNormal\">}<br \/><span class=\"caption\"><br \/>Figure 25: &#8211; Event Listener Installation Code<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\">Once the addin has been deployed, it will automatically take affect for any NUnit tests executed.&#160; There is no need to modify the tests.<\/p>\n<p class=\"MsoNormal\"><b>Deployment and execution<\/b><\/p>\n<p class=\"MsoNormal\">After you have successfully created your required addin, you will need to actually deploy and install it.&#160; One limitation of the addins is that they can only be installed into the same version of NUnit as they were compiled against; so, if someone compiled an addin against 2.4.5, then it wouldn&#8217;t work in 2.4.6.&#160; <\/p>\n<p class=\"MsoNormal\">To install the addin, you need to copy the assembly into the addin folder in your NUnit folder.&#160; For example, C:\\Program Files\\NUnit\\2.4\\addins\\, this could vary on different NUnit installations.&#160; You will also need to install the addin on any machines that will execute the test suite, such as build servers.&#160; When NUnit loads, it automatically searches for assemblies in this directory and attempts to load them.<\/p>\n<p class=\"MsoNormal\">In terms of executing tests containing your addin, the NUnit GUI and console application will support your addin correctly.&#160; However, support within 3rd party runners depends on the runner.&#160; TestDriven.Net works with all types of NUnit extensions, whereas ReSharper does not support any type of extensions.&#160; This is something to keep in mind when developing and executing. <\/p>\n<p class=\"MsoNormal\">Once your addin is installed and your tests are executing, you might find that you need to debug into your assembly to fix problems. The solution is to use the <b>Attach to Process<\/b> option within Visual Studio.&#160; After you have set breakpoints within your code, I always <\/p>\n<ol>\n<li class=\"MsoNormal\">start the NUnit exe,  <\/li>\n<li class=\"MsoNormal\">attach to the NUnit process,  <\/li>\n<li class=\"MsoNormal\">load my test assembly using the addin <\/li>\n<\/ol>\n<p class=\"MsoNormal\">at which point your debugger should kick it and allow you to step through your code. <\/p>\n<p class=\"MsoNormal\"><b>Summary<\/b><\/p>\n<p class=\"MsoNormal\">In summary, NUnit 2.4.6 has a number of different ways of extending the framework for your own requirements and to tailor test behaviour for different scenarios.&#160; The article has demonstrated how to extend NUnit via the built-in extension points which are Suite Builders, Test Case Builders, Test Decorators and Event Listeners.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>If you want to get serious with Unit Testing, then you&#8217;ll need to understand how to extend the NUnit framework in different ways  for your own particular test requirements and how to tailor test behaviour. Test Expert Ben Hall, of the SQL Generator team, shows how it is done, with special reference to the art of testing SQL code.&hellip;<\/p>\n","protected":false},"author":221832,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4204,4846,4150],"coauthors":[],"class_list":["post-355","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-tools","tag-nunit-unit-test-free-code-example","tag-sql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221832"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=355"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/355\/revisions"}],"predecessor-version":[{"id":90941,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/355\/revisions\/90941"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=355"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}