This is an intro into Testing with MS Visual Studio, just simple basics to get you started, so you can see how it works, and give you a few ideas on how to do it. I will be using VS 2008, but it should work for 2005 as well.
So Lets start with a New Project. I chose a Console Application in the Windows Visual C# for simplicity. Name it and click ok. Now before we get started, make sure you have Debug and Test Tools, toolbars on. This will help us running our test code.
Ok now we need some stuff to test. So we are going to use a basic circle to explain things. So go to your solution explorer and on the project, right click > add class, and call it Circle.cs then copy this stub class below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace TestTut {
class Circle {
private Point myPoint;
private double myRadius;
/// <summary>
/// Constructor for circle, default location, able to pass radius
/// </summary>
/// <param name="r">radius of the circle</param>
public Circle(double r) { }
/// <summary>
/// Constructor for circle, able to pass in both
/// location and radius
/// </summary>
/// <param name="loc">Cordinate point circle lies on</param>
/// <param name="r">radius of the circle</param>
public Circle(Point loc, double r) { }
/// <summary>
/// Circle Property for radius. Get and Set radius of circle
/// </summary>
public double Radius {
get { return 0; }
set { double stub = value; }
}
/// <summary>
/// Circle Property for diameter. Get and Set diameter of circle
/// </summary>
public double Diameter {
get { return 0; }
set { double stub = value; }
}
/// <summary>
/// Calculate the circumference of a circle within 2 decimal places
/// </summary>
/// <returns>
/// returns the double value of the circumference
///</returns>
public double getCircumference() {
return 0.0;
}
/// <summary>
/// Calculate the area of a circle
/// </summary>
/// <returns></returns>
public double getArea() {
return 0.0;
}
/// <summary>
/// The pie-shaped piece of a circle 'cut out' by two radii.
/// </summary>
/// <param name="theta"> the angle between the radii must be
/// between 0(exclusive) and 360(exclusive)</param>
/// <returns>returns the area of the sector</returns>
public double getSectorArea(double theta) {
return 0.0;
}
/// <summary>
/// Calculates the length of a side of a
/// square that is circumscibed
/// inside of the circle (Really make sure ur test code is working)
/// </summary>
/// <returns>Returns the length of one side of the square</returns>
public double lengthOfCircumscribedSquare() {
return 0.0;
}
}
}
So these stubs are going to be what were going to test and we are going to pretend that the developers are still currently developing them (all we know is how they are supposed to work)
Now once we have that, go to the menu Test > New Test. Select Unit test and name the file Test_Circle.cs and create a new Project (I called it Testing). See Fig.1 to make sure you have a similar Solution explorer to me.

Open up Test_Circle.cs, and let’s take a look at what Microsoft did for us.
First note what namespace has been imported:
using Microsoft.VisualStudio.TestTools.UnitTesting;
This is critical to making test classes, methods, and cases. Next take a look at that [attribute] that has been given to the class:
Testing{
[TestClass]
public class Test_Circle {...}
}
This will tell Visual Studio how to make the class behave. Now delete all the code inside the class except TestMethod1 (leave its attribute!). The reason we are doing this, is because we aren’t going to create an instance of this test so we don’t need a constructor, and also we don’t need the TestContext either. So let’s clear clutter and get on with the good stuff.
----------
We are going to deal with 3 test method attributes in this tutorial
[TestInitialize]
[TestCleanup]
[TestMethod]
And the first 2 are real easy in concept. TestInitialize will be run before every TestMethod. We do this if we have a lot of setup to be able run a big test (i.e. you need to have a few managers running to get certain methods, or you want to have certain variable initialized before a test, or you want to have some thread running). TestCleanUp, runs after every TestMethod. We do this to shutdown service or de-allocate memory etc...
In our case we won’t really need it but we will put it in for good practice.
So before our TestMethod 1, let’s put some variable declarations and our TestInitialize and TestCleanUp methods in. Since we are testing circles I figure we will want a Circle object, a point, and radius. Take note of the name of the circle I create, it will be important later. In the Initialize method, all I am doing is creating a random location for the point, and giving a default 1 value to radius, don't worry it will change. I'm leaving the Circle un-instantiated now, so we can do more testing with it. In the CleanUp method, I am just clearing all the variables for a fresh start for the next test method. (Make sure you add your other project's namespace and reference to you Test_Circle.cs so u can use Circle!)
Here’s what your class should look like now:
Test_Circle.cs
So let’s rename TestMethod1 to Test_Properties. This is a really basic test just to make sure the accessors are working and the constructor is setting the variables (often trivial enough to omit, since accessors are pretty basic). Place the following code inside of Test_Properties method:
actual = new Circle(radius);
This is valid because actual was declared as class variable, and radius is not null because the TestInitialize will have run by this point. This leads us to the core way of comparing and testing; Asserts :cheer:
Asserts are apart of Microsoft.VisualStudio.TestTools.UnitTesting so we already to go with using them. The Assert class is filled with static methods used to compare data. The most common and the one we will primarily use is: AreEqual.
Now when dealing with Assertions you are compare what is expected to what is actually happening. Now when looking at the parameters for AreEqual we get (object expected, object actual, string failure_message).
So lets put that to use; add an assert method for the radius in test properties right below the new circle line, then make another one for Diameter (I will add an expected variable to help visualize the emphasis on expected and actual.
double expected = radius; Assert.AreEqual(expected, actual.Radius, "Radius accessor is not returning radius properly"); expected *= 2; Assert.AreEqual(expected, actual.Diameter, "Diameter accessor is not returning radius properly");
Congrats now you are set up to run your first test, and here you have some options. And we will see what those Asserts do too. Now if we want to run the whole TestMethod through completion we can run Test in Current Context. This is done by right clicking somewhere in the method and going to "Run Tests", or Test>Run>Test in Current Context, or ctrl+r,t. Or if you want we can step through with the debugger u can click on the tool bard that we setup "Debug Tests in current context" or ctrl+r, ctrl+t. if your debugging I suggest putting in break points (click on the line to left of the line number to toggle) so the debugger will stop part way through.
You should get this when you "Run Tests"

What happened here, was the code was compiled and ran, but when it got to the first assert through an error because they were not right. This is because "the developers" (aka we) didn’t define our Radius and Diameter Properties. Note that the test will go until the first unhandled exception. So the order that you assert things are important (smallest to biggest is a good mindset).
let’s quickly change our Circle properties from 0s to what the should be:
/// <summary>
/// Constructor for circle, default location, able to pass radius
/// </summary>
/// <param name="r">radius of the circle</param>
public Circle(double r) {
myRadius = r;
myPoint = new Point(0, 0);
}
/// <summary>
/// Constructor for circle, able to pass in both location and radius
/// </summary>
/// <param name="loc">Coordinate point circle lies on</param>
/// <param name="r">radius of the circle</param>
public Circle(Point loc, double r) {
myRadius = r;
myPoint = loc;
}
/// <summary>
/// Circle Property for radius. Get and Set radius of circle
/// </summary>
public double Radius {
get { return myRadius; }
set { myRadius = value; }
}
/// <summary>
/// Circle Property for diameter. Get and Set diameter of circle
/// </summary>
public double Diameter {
get { return myRadius*2; }
set { myRadius = value/2; }
}
Run your test again, and it should pass! Which means our constructor and accessors (Properties) are working. So lets try something a bit harder; getCircumference(). (C = 2*PI*r or C= PI*d)
Once again we will right the test case first pretending we can’t see the Circle class. start by writing a new method (with the TestMethod Attributes)
and then creating an actual and expected objects. Finally assert their equivalence. Look something like this?
[TestMethod]
public void Test_Circumfrence() {
actual = new Circle(radius);
double c = actual.getCircumference();
//We round because the method description says it will rounded
//to 2 decimal places, so we need to make sure we do the same
double circum = Math.Round( Math.PI*2*radius,2 );
Assert.AreEqual(circum, c, "Circumferences differ");
}
And here is the dev code to use. For this I used a different formula, just to illustrate that we are not just comparing the same formula.
/// <summary>
/// Calculate the circumference of a circle within 2 decimal places
/// </summary>
/// <returns>returns the double value of the circumference</returns>
public double getCircumference() {
return ( (( 16 / 5 - 4 / 239 ) - ( 1 / 3 * ( 16 / 53 - 4 / 2393 ) ) ) + .14)*2*myRadius;
}
That leaves 3 more methods to fill out and test, and I urge u to try and find a creative way for lengthOfCircumscribedSquare. But before I let you go off and try it all on your own. I will show you one more test technique
(This will be expanded upon in my next tutorial).
While simply Testing the whole object at the end Assert.AreEqual( circle1, circle2); will not give us very good information as to why it fails, so usually you want to try and assert almost every variable. But what happens if a method throws an error. For example our getSectorArea() will throw an ArgumentException if your input is not in the specified range. Well if that’s the proposed functionality, then we ought to test for that as well! But the problem is this will fail:
[TestMethod]
public void Test_gSA_Bad() {
double d = 9001;
actual = new Circle(radius);
actual.getSectorArea(d);
}
And our beloved Asset class has methods to test exceptions. That is why we have the "ExpectedException" attribute (Yay)! What this means is we are going to actively look for a certain type of exception to be thrown, if it is the Test will pass. To make your method you pass ExpectedException an argument in your attribute line right after the TestMethod.
[TestMethod, ExpectedException(typeof(ArgumentException))]
You run it, and the test fails. So now our awesome developers finally get around to finalizing getSectorArea():
/// <summary>
/// The pie-shaped piece of a circle 'cut out' by two radii.
/// </summary>
/// <param name="theta"> the angle between the radii must be
/// between 0(exclusive) and 360(exclusive)</param>
/// <returns>returns the area of the sector</returns>
public double getSectorArea(double theta) {
if( theta <= 0 || theta > 360 )
throw new ArgumentException("Angle must be between 0 and 360");
return (Math.Pow( myRadius, 2) * theta)/2;
}
And now it should pass. But we should still right another method to test the mathematical correctness too. So make a Test_gSA().
So that’s it, those are your basics. Clearly when you get into test more complicated systems and equations you will truly see the usefulness of Testing. This will also mean the more creative you are writing your test cases, the more helpful you will be for developers finishing their code.
I have incorrectly finished Circle for you, try and make test cases based off the stubs before you download it, and see if you can figure out what is wrong! Good Luck
Attached File(s)
-
Circle.cs.txt (3.1K)
Number of downloads: 4761




MultiQuote





|