Strengthening Visual Studio Unit Testing



Hardcoded path closely

Use of unit testing a new project wizard to add the test is a very easy thing.This convenient feature can save you hundreds of hours of typing time (this should be Microsoft's developers to receive a lot of costs).However, some things happened behind the scenes, and cause you to be sad: the path is hardcoded!This is a problem, for example, a test when you move to another machine or directory occurs.I want a Visual Studio 2005, Service Pack allows you to set a starting path for the test, hardcoded path to use relative paths.At present, however, easy way to solve the hardcoded path is a charity in the team dictator, it is always judging and all the drive and path of the promulgation.If it is a small project, this solution is very good.Another, some utility work area will be in your path environment variable reference% testdeploymentdir%.When the test run when it is set.

Hardcoded paths in the first place is VSMDI file, this file is a large package containing a simple skin test list.When you open a VSMDI file, then it can not find the test set or TESTRUNCONFIG file, you will be prompted for these projects that location.I found something interesting the next time I open the same VSMDI file, it will find all the stuff.Obviously, some storage and then update the path to somewhere, but VSMDI file itself has not been changed.I would VSMDI file resides in the directory found in a hidden file named name . VSMDI.OPTIONS.

When I opened the VSMDI.OPTIONS file (it is a common XML file), I shook my head, I feel the same frustration.As you can see in Figure 1, as in VSMDI file search path is clear there is support for Visual Studio user interface, but there is no way you can set the search path.(In addition, there is no reason for these VSMDI files are hidden ah.) So, when I think in a different directory structure using VSMDI file, first copy an example VSMDI.OPTIONS file to the appropriate directory, and then manuallyedit it, in the assembly and TESTRUNCONFIG file, add the path.For this part of the source code, I have a folder in the BaseVSMDIOPTIONSFile example out of a file.

The main reason to use VSMDI file that you can specify a list of tests to run - in the dynamic development process, it is very useful because it allows you to run those specific tests, these tests and the code associated with your work.In a test set to run all the tests, you can use the console test runner, MSTEST.EXE.In a large number of command-line options, but you only need "/ testcontainer" option, which specifies the procedures included in the test set.In addition, you can use the "/ resultfile" to specify the results file name.When using MSTEST.EXE, you do not have to worry about VSMDI file.In the next section, I will discuss a MSBuild.EXE task, it can be run automatically in the directory structure found in all the tests, so you can avoid and VSMDI files together.

Hardcoded path you find the second location is in the TESTRUNCONFIG file; point to the instrument and the strong key file contains the hardcoded path to the assembly.I have pointed out the best way to solve this problem is when you run a different test directory structure to use a different TESTRUNCONFIG file.Because there is no way to create a new TESTRUNCONFIG files, you need to copy an existing file to the machine location, and then edit it using Visual Studio.If the drive and directory on a different, IDE and MSTEST.EXE about the path used to process TESTRUNCONFIG related files, but you must manually edit them.

Because it itself is not doing code coverage testing tool, so there is no way to stop from the command line has been manually compiled assembly code execution coverage.If you use ASP.NET to work, you need Visual Studio integrated development environment to do code coverage to create the right set of tools, then make it into a tool.

Manual do code coverage is a three-step process.The first step is to realize that the assembly code you have them covered in the hook (hooks).The second step is to begin to monitor the process, and then tell it to overwrite the file in which the preparation.Any run-time load monitoring process has been achieved their coverage of the binary data to output file.The final step is to close monitoring, the preparation of CONVERAGE file.I've made a Converage.Targets file, you can use MSBuild to automate this process together.Figure 2 shows some files; you can download from the MSDN ® Magazine Web site to all of the file.

Figure 2 When you visit, you will see that I wrote in Bugslayer.Build.Task.DLL a task to run the monitoring process.Figure 3 shows in its Visual Studio.

When first writing Civerage.TARGETS, I use the Exec task execution VSPERFCMD / START: Coverage / OUTPUT: $ (OutputCoverageFile), but in doing this time there is a serious mistake, MSBulid.EXE completely in the call hung up.VSPERFCMD.EXE produce the actual monitoring process, VSPERFMON.EXE.If you run the command prompt VSPERFMON.EXE, the process will stay connected, and the process that spits out other activities, the project file so you can not call it directly.

This problem occurs in MSBuild.EXE, the breed in an event, this event is VSPERFMON.EXE bInheritHandles marked with VSPERFCMD.EXE from the process of creation to CreateProcess, and is set to "true."Handle any process that began with a succession will be suspended under the MSBuild.EXE.Therefore, I must approach the task from ITask.Execute call Process.Start, through this operation to make MSBuild.EXE everything under the normal operation.

Together with the GenericTest and EXEs

If you have received an EXE program based on the existence of the test system, type in the document discusses GenericTest may harm your curiosity.When running in a dependency unit testing nine EXE as a batch file to work on the project, I can use rapid GenericTest types of packaging a number of automated processes that exist in the code.Although there are some catch.The first obstacle is GenericTest allow small 0 as a successful return value from the EXE.That is not a big deal, but considering GenericTest advanced features, I am very frustrated to see the area with an acceptable exit code as simple things are missing.

GenericTest of a larger problem is that it is a bastion of hardcoding.Fortunately, you can easily point out the relative path to sandwiches.If you have to GenericTest exist C: FOO, in fact the test from the C: FOOTestResults _ _ Out started.Thus, if the implementation is GenericTest to EXE file C: FOO, you can use ./././< name>. EXE to run as a program.Unfortunately, almost GenericTest of other things from the drive to be hard-coded.Interestingly, external to the binary directory that you copied to each run in place.Even if you change your code, you can re-run the test in the previous version to regenerate the problem.

Features a convenient manner, GenericTest type will capture the standard output to locate anything in the outcome document to provide a running log.Unfortunately, this seems like a catch problems in the extraction of some information that will lead to test drive the process to hang.But most of the test program will not find time in seconds in the 100 lines of output.

Create unit tests

When it comes to testing, Visual Studio real magic is when you right click in the editor, a method, it can be wonderful to create your unit test options.This feature is very good, you can easily add unit tests fast.However, I encountered a small philosophical question, it allows you to create direct access to the class and access to unit test private methods.

Testing tool allows direct calls for private or protected methods of the controversy is that it reduced the test (just write less code), and to help broaden the code coverage.These arguments are very tempting, but I agree with this view, is that unit testing should only occur through the public interface.Unit testing is code for the first time, how you want to use it toward the other direction to adjust the test.If there are private methods that you do not short circuiting and direct calls to their circumstances can not be fully tested, I must know if the code needs to be registered.In order to prevent the accidental creation of a direct call to unit test private methods to find the creating unit test dialog box, click the filter in the upper right corner, and then empty the display of non-public projects.

I am by no means a absolutist.I'm sure there are some examples which will help in the sample call private methods.However, because the tool only allows you to do something does not mean you will rely on it.Unit testing is testing the first stage, it is white box testing you start the first position.

Using NUnit

I have some projects in the project we have been in a test system to expand NUint made a great investment.(For. NET Framework 2.0 works about to be released new version) in the first example, we want to code in Visual Studio NUnit and test systems are portable.When the scheme this time, I came across something cool that requires minimal code changes, and allow code to work with NUnit and Visual Studio.

I have some projects in the project we have been in a test system to expand NUint made a great investment.(For. NET Framework 2.0 works about to be released new version) in the first example, we want to code in Visual Studio NUnit and test systems are portable.When the scheme this time, I came across something cool that requires minimal code changes, and allow code to work with NUnit and Visual Studio.

# If! NUNIT
using Microsoft.VisualStudio.TestTools.UnitTesting;
# Else
using NUnit.Framework;
using TestClass = NUnit.Framework.TestFixtureAttribute;
using TestMethod = NUnit.Framework.TestAttribute;
using TestInitialize = NUnit.Framework.SetUpAttribute;
using TestCleanup = NUnit.Framework.TearDownAttribute;
# Endif

I need to do is to use the NUnit test attribute change my ways for the TestMethod, then I have a way to work in both the test code.

TimeOutAttribute

Most of the properties of the document contains the summary of course very good.However, one of the most important attribute, TimeOutAttribute not included in the API documentation.When TESTRUNCONFIG file allows you to specify all the unit tests timeout value, TimeOutAttribute lets you specify a single test may take the maximum number of milliseconds.I found these links in the database TimeOutAttribute test methods have no value, so I pay close attention to these queries.Please note that some of the time value contains the time the test runner.In addition, the speed and performance will affect the time.Experimental tests using your time to choose a look at how your system works.

TestContext class we just briefly relate to, it is to be Unit Test Wizard to add the incoming TextContext property.The main discussion is about the time when you are using DataSourceAttribute TestContext class access to data through the use of the line.TestContext class has a lot of content.Documents show TestContext class marked as abstract, but in fact support your unit test's source type is UnitTestAdapterContext, it comes from Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter.dl, you can Common7IDEPrivateAssemblies found this DLL file.You can use. NET Reflector View UnitTestAdapterContext order to understand how it works.

Perhaps this class supports the most important method is to WriteLine, you can use it to add additional output to the separate test results.All will appear in the report prepared by the additional information section.To find out what the test is running or what the test began in the directory, you can use a single domain TestName TestContext property and TestDir.Finally, if you want to set the time for all or part of the testing device, called TestContext.BeginTimer and TestContext.EndTimer.In the standard console output part time data will appear in the test run results.

Write code for you

I have mentioned, I've included a unit testing together with its real unit.Bugslayer.Utility.DLL is a drag and drop between projects I have in a collection of useful code.ArgParser class is a command-line argument of class, this class is based on the old. NET Framework SDK WordCount example of the class.SystemMenuForm class is a Windows Form, this form allows you to add menu items in the system, and as a regular time to respond to clicks.

The reason I write GlobalMessageBox is because each time a message box is very tired when I see the code of the error, Specify MessageBoxOptions.Rules when using a message box, you need to browse categories, and then clear whether the RightToLeft property is set to Yes.If so, you must call the appropriate MessageBox.Show load MessageBoxOptions markup passed.GlobalMessageBox to me concerned about this, inhibition of the code error and allow me in the right-to-left language systems work correctly.

For the complete unit test Bugslayer.Utility.DLL in Bugslayer.UtilityTests Bugslayer.Utility.Tests directory.CS files in a variety of tests, including 39 to provide over 92% code coverage.Since this is a Windows Forms unit, the unit made the message box and controls, you can not run it unattended, but it can run in 15 seconds.

For the complete unit test Bugslayer.Utility.DLL in Bugslayer.UtilityTests Bugslayer.Utility.Tests directory.CS files in a variety of tests, including 39 to provide over 92% code coverage.Since this is a Windows Forms unit, the unit made the message box and controls, you can not run it unattended, but it can run in 15 seconds.

Name and Location

MSTEST.EXE the unpaired part is naming its output.If you use / RUNCONFIG option to operate a TESTRUNCONFIG file, output file will use the provisions in that file naming convention.If you do not use / RUNCONFIG, or set as the default, all output is written. TestResults _ .I recommend using to quickly identify the name.

MSTEST.EXE offers / RESULTSFILE option, but this will result in the output file name of the missing stamp.Also, if you specify to / RESULTSFILE file name out, MSTEST.EXE will fail.I hope that the work to specify a focus on the details of my name, but do not need to manually add a time stamp.

You may want to possible solution is to use VSMDI test source data file that you used to see the Test Manager window.In fact, MSTEST.EXE no / TESTMETADATA option to load and run the tests.The problem is you can only specify a VSMDI file.

One possible solution is to create a separate VSMDI file, this file in your code inside the file to import all the other VSMDI.It can indeed work, but it also presents another maintenance task to remember every time you add new tests to the code.

Note that when running VSMDI files you can not tell the IDE or MSTEST.EXE the output file placed.Output file points to the VSMDI file storage directory.Recommended to save the test in a directory, the directory in the source code under version control, so if you share the project, all the test code will follow it.

As VSMDI file as part of each test, and there is no way to focus on output, the output will be around your source code is distributed.This is not a big deal, but it means you have to manually organize the source tree.In dealing with some of the results of test run, I want a simple way to handle this.

A better MSTEST.EXE

Based on this discussion, I understand there are four features that I want to add to MSTEST.EXE.The first is a method to dynamically discover all the unit tests, and as small as smoke tests to run them.The second is a simple method to identify a similar test run, not just read the timestamp.The third is to ensure that all test output targeted to a single location.Finally, I want a very easy way to remove the independent test runs, regardless of their source tree in any location.

These requirements strongly urge MSBuild.Bugslayer.Build.Tests.DLL the MSTestTask packaging MSTEST.EXE so you can get all of the control.As you can see the code, you will notice that it is obtained from the ToolTask class, and is produced by the Microsoft.Build.Utilities.DLL assembly.When writing a package, a command-line tool (as it did most of the increase) build task, this task, ToolTask what you want to use.

For some tools, you need to do is define your unique attributes, the three methods and one property overloaded.Property is ToolName, it returns the name of the tool executable.GenerateFullPathToTool method returns the complete drive, path and file name into the tool itself.In order to validate these parameters, you need to override ToolTask.ValidateParameters way, if everything is normal, then the return value is true.In order to compile the actual command-line into the tool, then use the overloaded ToolTask.GenerateCommandLineCommands CommandLineBuilder class or I do it the simple extension ExtendedCommandLineBuilder.

For all possible command line parameter to run MSTEST.EXE /?.When it is time to specify the output file name needs ResultsFile.You also need to set parameters or TestContainer TestMetaData parameters shown as separate source data files or test container.

For all possible command line parameter to run MSTEST.EXE /?.When it is time to specify the output file name needs ResultsFile.You also need to set parameters or TestContainer TestMetaData parameters shown as separate source data files or test container.

However, I am a long-term plan is to expand MSTestTask test attribute wildcard to the test to allow the name of execution is passed.That will allow you to easily perform only those tests meet the specific prefix.With properties in TestContainer was adopted by the assembly, which will be merely a series of reflection, to find a TestClassAttribute compliant libraries and the expression of some of the methods with TestMethodAttribute.

MSTestTask other operations in part from RunTests.Targets file, you can. Build a directory that contains the source code found in the document.It includes a very cool ExecuteAllTests object that you specify the directory in the beginning, the entire structure to find all the unit tests, GenericTests, WebTests and OrderedTests, and then execute them.You can think of ExecuteAllTests object is a unit test for automated regression testing for.When you add a new test, it will automatically execute them.Included in the code download code is very wise to use RunTests.Targets exclude file to get what we want.To view an example of using the RunTests.Targets, look SmokeTest.proj, it shows the code for all smoke tests.

In. Build directory last TARGETS file is MSTestCleanUp.Targets.Like its name implies, its job is to find the directory that contains all TestResults as a path and then delete them.It is to use a good example of transformation, as MSBuild tasks in RemoveDuplicates same.Use MSTestClean-Up.Targets, you do not be afraid of the other damage your source file directory.

Cover, packaging

If you do not say, I will the new Visual Studio 2005 unit testing tool is very excited.DataGrids such as ASP.NET and procedures in this book by all the attention, but when you get time to program, test tools will bring great impact.I can guarantee you're using testing tools more time to spend, your code will become better.

Tip 73 is a unit test you can control the default programming language and when a new unit test is created unit test wizard which entries can be added to the inside.To the Options dialog box, expand Test Tools node, and then go to test the project properties page.In that, you will see the default type of test items for each language combobox and select the default file type.If you're like me, you create a second unit test you will clear the "About Test Projects" describes the file.

Tip 74 attempts to an assembly of all the unit tests saved to a single test assembly.The one to one mapping from the maintenance point of view.However, when the assembly grows, the number of tests will become very large.I like to prefix the name into the test method, because they test the characteristics.This can be easily grouped.For example, in Bugslayer.Utility.Tests.DLL assembly, testing began on GlobalMessageBox class in "GNB_"