Introduction
Test Driven Development (TDD) is one of the core programming practices of XP. TDD completely turns traditional development around. Instead of writing functional code first and then test code as an afterthought, write test code before functional code. TDD revolves around three basic activities: writing a test, writing code to pass the test, and refactoring the code to make it flexible and easier to understand. TDD takes a different, extreme approach to ensure that we test all code, all the time.
This article explains about the Test Driven Development approach for a library project which can automate COM+ Administration Task.
The COM+ Administration Task Library provides the following features:
- Add a COM+ application
- Delete an existing COM+ application
- Start an existing COM+ application
- Shut-down an existing COM+ application
This article covers an NUnit client application development (test code) and refactoring the library code to pass the NUnit test. This article does not cover the user interface for the library.
Test Driven Development of the COM+ Administration Library
Here are the steps for the Test Driven Development of the COM+ Administration Task:
Step 1:
Create a client application and provide a test method to test one of the above mentioned library features. Start with testing the "Add a COM+ Application" feature.
Build the application. We will get build errors as there is no reference to the library application (in fact, the library application has not been developed yet).
Step 2:
Create the COMPlusAdministration library application and provide skeleton code for the "Add a COM+ Application" feature.
Step 3:
Build the client again after providing the reference to the library application.
Step 4:
Run NUnit to test the Test
method in the client application. This will fail as there is no complete implementation for the "Add a COM+ Application" feature in the library.
Step 5:
Implement the complete functionality for the "Add a COM+ Application" feature in the COMPlusAdministration library application.
Step 6:
Run the NUnit test again to make sure the test passes for the "Add a COM+ Application" feature.
Step 7:
Repeat the above steps after adding new test methods (in the client application) to test other library features such as Start Application, Delete Application, and Shut-Down Application.
Let's look at the above steps in detail.
Client Application (Step 1)
For this Test Driven Development, our client application is a Windows based application.
Start by creating new Windows Application project and name it as NUnitClient.
When NUnit opens the client application, it looks for the classes with the TestFixture
attribute. The TestFixture
attribute indicates NUnit to look for methods with the Test
attribute and run those methods. (Please look at the NUnit documentation for more details on the TestFixture
and Test
attributes.)
In order to run NUnit, we must add a class to our client application with the TestFixture
attribute. Add the NUnitClient.cs file to the project using Project -> Add New Item. Open the NUnitClient.cs file and add the [TestFixture]
attribute to the NUnitClient
class.
[TestFixture]
public class NUintClient
{
public NUintClient()
{
}
}
Add a CreateApplication
method to the NUnitClient
class with the [Test]
attribute. We use this method to test the Create a COM+ Application functionality of the COMPlusAdministration library application.
[TestFixture]
public class NUintClient
{
public NUintClient()
{
}
[Test]
public void CreateApplication()
{
COMPlusAdmin objCOMPlusAdmin = new COMPlusAdmin();
string strReturn = objCOMPlusAdmin.CreateApplication("EventOverlay",
"EventOverlay Application");
Assert.AreEqual("CreateApplication Success",strReturn);
}
}
As TestFixture
and Test
attributes are part of NUnit, we need to add a reference to NUnit Components to avoid build errors.
Add a reference to the NUnit components using Project –> Add Reference. Also, add these namespaces to NUnitClient.cs.
using NUnit.Tests.Assertions;
using NUnit.Framework;
using NUnit.Core;
using NUnit.Extensions;
Now, try to build the client application. The build fails, because there is no reference to the COMPlusAdmin
class in this application.
To solve these build errors in our client application, we need to have a reference to a component with the COMPlusAdmin
class in it.
Let’s create a COMPlusAdministration
component with the COMPlusAdmin
class and the CreateApplication
method in it.
COMPlusAdministration Application (Step 2)
Start by creating a library project and name it as COMPlusAdministration.
Rename Class1.cs to COMPlusAdmin.cs and add a CreateApplication
method to it with bare minimum code.
public string CreateApplication(string strAppName,
string strAppDescription)
{
string strMessage="";
return strMessage;
}
Build the library application.
Build Client Application (Step 3)
Add the library reference to the client application. Also add the COMPlusAdministration
namespace to NUintClient.cs.
using COMPlusAdministration;
Now, build the client application. This time, it will build without errors as we added the COMPlusAdministration library reference to the application. Now, we are ready to run the client application using NUnit.
Run NUnit (Step 4)
Run this application using NUnit2.0. NUnit will throw an error message for the “CreateApplication
” method, saying:
expected : < “CreateApplicaiton Success” >
but was : < “ ” >
The CreateApplication
method in the COMPlusAdministration library is returning an empty string as there is no implementation for this method. However, in the client application, we are expecting “CreateApplication Success” as the return value from this method.
Assert.AreEqual("CreateApplication Success", strReturn);
Now, our goal is to pass the client's CreateApplication
method. NUnit will pass this method only when the CreateApplication
method of the COMPlusAdministration library returns "CreateApplication Success".
Provide Functionality in COMPlusAdministration (Step 5)
It is time to implement the complete functionality for the CreateApplication
method.
The CreateApplication
method will return either "CreateApplication Success" or "CreateApplication Failure”, depending on the success or failure of the CreateApplication
method. Please check the code mentioned below for the CreateApplication
method:
public void OpenCatalog()
{
objCatalog = new COMAdminCatalog();
objCatalogColl = (COMAdmin.COMAdminCatalogCollection)
objCatalog.GetCollection("Applications");
}
public string CreateApplication(string strAppName, string strAppDescription)
{
string strMessage="";
try
{
OpenCatalog();
COMAdmin.COMAdminCatalogObject obj=(COMAdmin.COMAdminCatalogObject)
objCatalogColl.Add();
obj.set_Value("Name",strAppName);
obj.set_Value("Description",strAppDescription);
objCatalogColl.SaveChanges();
strMessage= "CreateApplication Success";
}
catch(Exception ex)
{
strMessage= "CreateApplication Failure";
}
return strMessage;
}
Before building the COMPlusAdministration library, add a reference to the COM +1.0 Admin Type Library.
We have implemented the “CreateApplication
” method; now, it is time to check whether the method is working properly or not.
Run NUnit (Step 6)
Run the client application again using NUnit and check for any errors. This time, NUnit must not show any errors if the CreateApplication
method successfully creates the COM+ application.
If the CreateApplication
method fails to create the COM+ application, it returns the "CreateApplication Failure” message. In this case, NUnit will not pass the CreateApplication
method, and will show an error saying that:
expected : < “CreateApplicaiton Success” >
but was : < “"CreateApplication Failure" ” >
Try modifying the CreateApplicaiton
method code until NUnit passed the method.
If the CreateApplicaiton
method successfully creates the COM+ application, you can see the new COM+ application in Component Services under the COM+ Applications root. In this case, it is EventOverlay.
Test Other Features (Step 7)
Test other COM+ administration tasks (Delete Application, Start Application, Shut Down Application) by creating test methods in the client application.
Here is the code for the DeleteApplication
, StartApplicaiton
, and ShutDownApplication
test methods in the client application:
[Test]
public void DeleteApplication()
{
COMPlusAdmin objCOMPlusAdmin = new COMPlusAdmin();
string strReturn = objCOMPlusAdmin.DeleteApplication("EventOverlay");
Assert.AreEqual("DeleteApplication Success",strReturn);
}
[Test]
public void StartApplication()
{
COMPlusAdmin objCOMPlusAdmin = new COMPlusAdmin();
string strReturn = objCOMPlusAdmin.StartApplication("EventOverlay");
Assert.AreEqual("StartApplication Success",strReturn);
}
[Test]
public void ShutDownApplication()
{
COMPlusAdmin objCOMPlusAdmin = new COMPlusAdmin();
string strReturn = objCOMPlusAdmin.ShutDownApplication("EventOverlay");
Assert.AreEqual("ShutDownApplication Success",strReturn);
}
Here is the functionality for the DeleteApplication
, StartApplication
, and ShutDownApplication
in the COMPlusAdministration library project:
public string DeleteApplication(string strAppName)
{
string strMessage="";
try
{
OpenCatalog();
objCatalogColl.Populate();
int nCount = objCatalogColl.Count;
for(int i=0; i < nCount ; i++)
{
COMAdmin.COMAdminCatalogObject obj =
(COMAdmin.COMAdminCatalogObject) objCatalogColl.get_Item(i);
if(strAppName == (string)obj.get_Value("Name"))
{
objCatalogColl.Remove(i);
objCatalogColl.SaveChanges();
break;
}
}
strMessage = "DeleteApplication Success";
}
catch(Exception ex)
{
strMessage= "DeleteApplication Failure";
}
return strMessage;
}
public string StartApplication(string strAppName)
{
string strMessage="";
try
{
bool bApplicationFound = false;
OpenCatalog();
objCatalogColl.Populate();
int nCount = objCatalogColl.Count;
for(int i=0; i < nCount ; i++)
{
COMAdmin.COMAdminCatalogObject obj =
(COMAdmin.COMAdminCatalogObject) objCatalogColl.get_Item(i);
if(strAppName == (string)obj.get_Value("Name"))
{
bApplicationFound = true;
}
}
if(true == bApplicationFound )
{
objCatalog.StartApplication(strAppName);
}
strMessage= "StartApplication Success";
}
catch(Exception ex)
{
strMessage = "StartApplication Failure";
}
return strMessage;
}
public string ShutDownApplication(string strAppName)
{
string strMessage="";
try
{
bool bApplicationFound = false;
OpenCatalog();
objCatalogColl.Populate();
int nCount = objCatalogColl.Count;
for(int i=0; i < nCount ; i++)
{
COMAdmin.COMAdminCatalogObject obj =
(COMAdmin.COMAdminCatalogObject) objCatalogColl.get_Item(i);
if(strAppName == (string)obj.get_Value("Name"))
{
bApplicationFound = true;
}
}
if(true == bApplicationFound )
{
objCatalog.ShutdownApplication(strAppName);
}
strMessage= "ShutDownApplication Success";
}
catch(Exception ex)
{
strMessage= "ShutDownApplication Failure";
}
return strMessage;
}
If all the test methods in the client application pass, then the library is unit tested and ready to use. As mentioned earlier, this article does not cover the user interface for the library.
Conclusion
Test Driven Development is a powerful technique that ensures that all of your code is tested. Another advantage is that Test Driven Development, when used properly, ensures that all written code is covered by a test. This can give the programmer a greater level of trust in the code.