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: May 7, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT This eSeminar will explore three popular games engines and how they empower developers to create exciting, graphically rich, and high-performance games for Android® on Intel® Architecture. Join us for a deep dive as experts describe the features, tools, and common challenges using Marmalade, App Game Kit, and Havok game engines, as well as a discussion of the pros and cons of each engine and how they fit into your development …

  • Download the Information Governance Survey Benchmark Report to gain insights that can help you further establish business value in your Records and Information Management (RIM) program and across your entire organization. Discover how your peers in the industry are dealing with this evolving information lifecycle management environment and uncover key insights such as: 87% of organizations surveyed have a RIM program in place 8% measure compliance 64% cannot get employees to "let go" of information for …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds