Completing the NUnit Project Template for .NET, Part 2

Introduction

In this article—Part 2 of 2—I will complete the project template by demonstrating how to modify the supporting script to add a reference to import the nunit.framework.dll, how to define the wizard launching file, add the VSDir file entries, and we will take our new test library, created by the template, for a spin around the block.

This second half of the article requires you to modify VS.NET-installed files. It is a good idea to make copies of these files before making modifications. Without an xcopy backup, you may have to re-install VS.NET if you make a mistake.

Modifying Wizard Script Files

In Part 1, we copied the ClassLibrary project template and renamed the containing folder TestClassLibrary. After using the ClassLibrary project template as a good starting point, we modified the template class file to reflect the code we want NUnit test projects to have. The next step is to modify script files and wizard launching files so that the vsWizard.dll—included with VS.NET—knows what elements to add to a new project.

Picking up where we left off, we need to modify a script file the vsWizard.dll uses to aid in creating the project. The relative path to one of these files is named scripts\1033\default.js. Default.js contains a Jscript event handler named OnFinish. OnFinish adds some elements to the newly created project. We need to extend the copied default.js file to call a method that will add a reference to the nunit.framework.dll. Listing 1 is almost an exact copy of the default.js file with the one necessary modification shown in bold.

Listing 1: The slightly modified scripts\1033\default.js.

//
// Copyright (c) Microsoft Corporation 2001-2002. All rights
// reserved.
//

function OnFinish(selProj, selObj)
{
  var oldSuppressUIValue = true;
  try
  {
    oldSuppressUIValue  = dte.SuppressUI;
    var bSilent         = wizard.FindSymbol("SILENT_WIZARD");
    dte.SuppressUI      = bSilent;

    var strProjectName  = wizard.FindSymbol("PROJECT_NAME");
    var strProjectPath  = wizard.FindSymbol("PROJECT_PATH");
    var strTemplatePath = wizard.FindSymbol("TEMPLATES_PATH");
    var strTemplateFile = strTemplatePath + "\\ClassLibrary.vbproj";

    var project = CreateVSProject(strProjectName, ".vbproj", 
      strProjectPath, strTemplateFile);
    if( project )
    {
      strProjectName = project.Name;    //In case it got changed

      var item;
      var editor;

      var strRawGuid = wizard.CreateGuid();
      wizard.AddSymbol("GUID_ASSEMBLY",
                       wizard.FormatGuid(strRawGuid, 0));

      strTemplateFile = strTemplatePath + "\\AssemblyInfo.vb"; 
      item = AddFileToVSProject("AssemblyInfo.vb", project, 
        project.ProjectItems, strTemplateFile, false);
      if( item )
      {
        item.Properties("SubType").Value = "Code";
      }

      strTemplateFile = strTemplatePath + "\\Class.vb"; 
      item = AddFileToVSProject("Class1.vb", project, 
        project.ProjectItems, strTemplateFile, false);
      if( item )
      {
        item.Properties("SubType").Value = "Code";
        editor = item.Open(vsViewKindPrimary);
        editor.Visible = true;
      }
            
      // new code here
      AddReferencesForWizard(project);
            
      project.Save();
    }
    return 0;
  }
  catch(e)
  {   
    switch(e.number)
    {
      case -2147024816    /* FILE_ALREADY_EXISTS */ :
        return -2147213313;

      default:
        SetErrorInfo(e);
        return e.number;
    }
  }
  finally
  {
    dte.SuppressUI = oldSuppressUIValue;
  }
}

AddReferencesForWizard is a function that we will implement in a second script file. The result of the behavior is that the new project created from the template, represented by the object named project, will have the NUnit assembly reference added to it.

The (relative path) VBWizards\1033\common.js contains behaviors available to all templates. Common.js is quite a bit longer, so Listing 2 only contains the code you will need to add to this file.

Listing 2: Two new methods added to VBWizards\1033\common.js.

function GetVBReferenceManager(proj)
{
  var VSProject  = proj.Object;
  var refmanager = VSProject.References;
  return refmanager;
}


function AddReferencesForWizard(proj)
{
  var refManager          = GetVBReferenceManager(proj);
  var isReferenceExpanded = IsReferenceExpanded(proj);
  refManager.Add("NUnit.Framework");
  
  if( isReferenceExpanded )
    CollapseReferenceNodes(proj);
}

GetVBReferenceManager returns an instance of the references collection associated with a project. AddReferencesForWizard adds a reference to nunit.framework.dll. Simply referring to the assembly by name is acceptable because NUnit strongly names its assemblies and registers them in the GAC when NUnit is installed.

After modifying the script files, our wizard is complete. All that's left to do is let the vsWizard.dll know about our new project template.

Define the Wizard Launch File

A wizard launching file is a text file with a .vsz extension. Each wizard launching file indicates the wizard class that is used to create a project from the template and parameters to that class. To create our wizard launching file, copy the Class Library's wizard launching file and rename the copy TestClassLibrary.vsz. In a default VS.NET installation, the location of these files will be c:\program files\microsoft visual studio .net 2003\vb7\vbprojects, and the contents of our wizard launching file are shown in Listing 3.

Listing 3: The TestClassLibrary.vsz wizard launching file.

VSWIZARD 6.0
Wizard=VsWizard.VsWizardEngine.7.1
Param="WIZARD_NAME  = TestClassLibrary"
Param="WIZARD_UI    = FALSE"
Param="PROJECT_TYPE = VBPROJ"

Define the VSDir File Entry

Technically, we have worked backward in implementing the project template solution. The first thing the vswizard.dll does is look in a specific location for a file with a .vsdir extension. The .vsdir file is used to tell the wizard where the wizard launching file is, which in turn indicates the location of the template files and scripts, and so on.

In a default VS.NET installation, the .vsdir file we need to modify is located at c:\program files\microsoft visual studio .net 2003\vb7\vbprojects\projects.vsdir. This file is a text file that contains information that describes how to display the project item template in VS.NET. Because our TestClassLibrary is very similar to the ClassLibrary, we can copy the ClassLibrary's .vsdir entry and make a few changes for our new template project. Listing 4 contains our .vsdir entry. It is important to use just one line when you add this entry although multiple lines are used here due to limited page real estate.

Listing 4: The VSDir entry for the TestClassLibrary.

TestClassLibrary.vsz|{164B10B9-B200-11D0-8C61-00A0C91E29D5}
                    |NUnit Test Library|20|#3001
                    |{164B10B9-B200-11D0-8C61-00A0C91E29D5}|4500|
                    |TestClassLibrary

The .vsdir entries are delimited by the pipe (|) symbol. Table 1 describes each of the .vsdir fields.

TestClassLibrary.vsz Relative path and file name of the wizard launching file
{164B10B9-B200-11D0-8C61-00A0C91E29D5} The CLSI for the VB Editor Factory
NUnit Test Library A new or resource id for the name of the template
20 The sort priority
#3001 A localized resource string
{164B10B9-B200-11D0-8C61-00A0C91E29D5} The CSLID or path for template icons
4500 Icon resource ID (we'll be using the same icon as the Class Library's icon)
<blank> Flags
TestClassLibrary The suggested base name for new projects

Testing the Wizard

After we modify the .vsdir file, we are ready to test our new project template. To test the project template, select File|Add New Project. Assuming the .vsdir file is prepared correctly, we will see the NUnit Test Library icon in the Add New Project dialog (see Figure 1). Select the template icon and a complete test library project should be created. If we completed all of the other steps correctly, the new project should compile and load in NUnit without modification.

Figure 1: Our new project template in VS.NET's Add New Project dialog.

Each time you want to create a new test library, you can use the new project template and add tests to it after the project is created. Over a period of weeks and months, this one template should save you many hours of writing repetitive code.

Summary

Have you ever heard of the notion of hyper-productive programmers? A hyper-productive programmer is someone who writes as much as ten or twenty times more code than their peers. How does this happen, you might ask? The answer is that hyper-productive programmers take short cuts, use code generators, and have a rhyme and reason for the things they do. Shortcuts, macros, code generators, and habits guide a hyper-productive programmer's actions.

Perhaps you strive to be a hyper-productive programmer or you already are. Either way, using project or item templates will result in code that is pre-written, always correct, and will increase your productivity.

About the Author

Paul Kimmel is the VB Today columnist for codeguru.com and developer.com and has written several books on object-oriented programming, including the recently released Visual Basic .NET Power Coding from Addison-Wesley and the upcoming Excel VBA 2003: Programmer's Reference from Wrox Press. He is the chief architect for Software Conceptions and is available to help design and build your next application.

The Lansing, Michigan area has started a new .NET Users Group. A well-run group offers great learning and networking opportunities and occasionally some free pizza and door prizes. Contact me at pkimmel@softconcepts.com if you live in mid-Michigan and are interested in participating.

# # #



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Hundreds of millions of users have adopted public cloud storage solutions to satisfy their Private Online File Sharing and Collaboration (OFS) needs. With new headlines on cloud privacy issues appearing almost daily, the need to explore private alternatives has never been stronger. Join ESG Senior Analyst Terri McClure and Connected Data in this on-demand webinar to take a look at the business drivers behind OFS adoption, how organizations can benefit from on-premise deployments, and emerging private OFS …

Most Popular Programming Stories

More for Developers

RSS Feeds