Browse DevX
Sign up for e-mail newsletters from DevX


Unit Testing in .NET : Page 5

You have been given the task of creating some business objects for a new .NET project. The UI has not been created (or designed) yet, so you start coding right away. After creating the first few objects, you decide that maybe you should do some unit testing. This article shows you how.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

You have already used two attributes provided by the NUnit framework: TestFixture and Test. TestFixture is used to mark a class that contains testing methods. There are a few restrictions on classes marked with this attribute; the class must have a default constructor and the class must be public or the NUnit GUI will not be able to detect it.

The Test attribute is used to mark specific methods inside a TestFixture class as a test method. These methods must not accept any parameters and cannot return any values.

The TestFixtureSetUp attribute is used to flag an Init method for constructing the test environment. This method is executed prior to the first Test method. Common tasks that are included in this method are to create and initialize any common objects that the test methods will use, so each Test method does not have to initialize the objects. This can help speed up the testing process.

The TestFixtureTearDown attribute is used to flag a Dispose method that can be used to clean up any object references created during the testing process. This method is executed after all Test methods are executed.

A TestFixture class can only have one TestFixtureSetUp method and one TestFixtureTearDown method. If more than one of either method is included, the class can compile but will not run during the testing process.

Listing 3 shows another test class for testing the Account class using these two attributes.

As you can see, one method depends on the results of the prior method, since the TextFixtureSetup runs only once before the tests start. If you want to reset your environment prior to or after each test method, see the SetUp/TearDown section, next.

The SetUp and TearDown attributes are similar to the TestFixtureSetUp and TestFixtureTearDown attributes. The big difference appears when they are executed. The SetUp method runs prior to each test method and the TearDown runs after each test method. These methods can be used to reset the environment after each test.

It is possible to use the NUnit GUI as the debugging application in your .NET project.
If I changed the TestFixtureSetUp and TestFixtureTearDown attributes in the above code to SetUp and TearDown, most of the tests would fail because the source and destination objects are removed and recreated after each test method is executed. I would have to modify the test values in the AreEqual methods to account for this modification.

The ExpectedException attribute causes a method to pass or fail based on whether the called method (in the business object) throws an exception of a specific type. If an exception of the expected type is thrown, the method passes. If the method throws an exception of a different type or no exception at all, the test method fails. It also fails if the thrown exception is inherited from the expected exception class. This attribute takes a parameter that is a Type. This is the Type of exception class it is expecting.

To illustrate this, I'll go back to the Account class and create a new exception class to be used to handle the Not Sufficient Funds problem. Add a new class called NotSufficientFundsException that inherits from the Exception class. Here is the code for this new class:

using System; namespace Bank { public class NotSufficientFundsException : Exception { } }

Next, change the Withdraw and Transfer methods of the Account class, as shown in Listing 4.

Then add two more test methods to the test class to test for this exception. The code looks something like this:

[Test] [ExpectedException( typeof(NotSufficientFundsException))] public void TestTransferWithNotSufficientFunds() { this.source.Transfer(this.destination, 1000.00f); } [Test] public void TestBalancesAfterException() { Assert.AreEqual(100.00f, this.source.Balance); Assert.AreEqual(300.00f, this.destination.Balance); }

When this code runs, it calls the Transfer method to transfer $1,000 to the destination account. The Transfer method calls the Withdraw method, which checks the current balance and determines that there is not enough money in the source account. It then throws the custom exception. The Transfer method catches this exception and throws it on to the test method. In this case, the test method passes because it is expecting that exception. However, if you change the transfer amount to $10 and run it again, the test method fails because the NotSufficientFundsException is not thrown by the Transfer method because there is enough money in the account to transfer.

The purpose of the additional test method is to make sure that the balances did not change after the NotSufficientFundsException was thrown. If the Transfer method does not throw the exception and the transfer is allowed, this last test fails because the balances are different.

The Ignore attribute tells NUnit not to run this test. It can be applied to either a TestFixture class or a Test method. Any TestFixture class or Test method using this attribute is flagged with a yellow indicator in the NUnit GUI after the tests are executed, showing that the test was skipped. These tests also show up on the "Tests Not Run" tab of the NUnit GUI. The Ignore attribute has an optional message that can be used to display a message on this tab to remind the user why the test is being skipped. The syntax for this is:

[Ignore("your message")]

Thanks for your registration, follow us on our social networks to keep up-to-date