Nunit Quick Start

Source: Internet
Author: User

Translator's order]

Throughout software development, testing has increasingly become an important part of software development. Generally, testing takes half or more of the time in a software development cycle. In the process of testing, unit testing is the first step in the long journey. Whether the unit testing is complete directly affects the efficiency of later integration testing. For unit testing, there are many software that can be completed automatically. nunit is one of them. This is a unit test software named in the same name as JUnit, which belongs to the xunit family (we can get this software for free in http://www.NUnit.org ).

[Body]

Let's start with a simple example. Suppose we are writing a banking application, and we have a basic class in this field-account. Accounts support deposits, withdrawals, and fund transfers. This account class looks like this:

Namespace bank {
Public class account {
Private float balance;

Public void deposit (float amount ){
Balance + = amount;
}

Public void withdraw (float amount ){
Balance-= amount;
}

Public void transferfunds (Account destination, float amount ){
}

Public float balance {
Get {
Return balance;
}
}
}
}

Now let's write a test -- accounttest for this class. The first class method to be tested is transferfunds.

Namespace bank {
Using nunit. Framework;

[Testfixture]
Public class accounttest {

[Test]
Public void transferfunds (){
Account source = new account ();
Source. Deposit (200.00f );
Account destination = new account ();
Destination. Deposit (150.00f );

Source. transferfunds (destination, 100.00f );
Assert. areequal (250.00f, destination. Balance );
Assert. areequal (100.00f, source. Balance );
}
}
}

The first thing to note is that this class is associated with a [testfixture] feature (attribute) -- this indicates that this class contains the test code (this feature can be inherited ). This class must be public, but its parent class is not limited. This class must also have a default constructor.

The only method in the class-transferfunds (), associated with a [test] feature-This indicates that it is a test method. The return value of the test method must be void and cannot contain parameters. In our test method, we initialize the tested object, execute the tested method, and check the object status. The assert class defines a set of methods used to check given conditions. In our example, we use areequal () method to ensure that both accounts have the correct balance after the transaction (this method has many reloads. the version we use in this example has two parameters: the first parameter is our expected value, the second parameter is the actual value ).

Compile and run this example. Suppose you have compiled your test code into bank. dll. Open the nuint gui (the installer will create a shortcut in your desktop and program menu), open the GUI, select File-> Open menu item, and find your bank. DLL and select it in the "open" dialog box. After the bank. dll is loaded, you will see a test tree structure in the left-side pane and a group of status panels on the right. Click the run button. the status bar and the transferfunds node of the test tree become red-our test failed. The "errors and failures" panel displays the following message: "transferfunds: Expected <250> but was <150> ", the stack trace panel at the bottom of the stack trace panel reports the location of the test failure statement in the code -- "at bank. accounttest. transferfunds () in C:/nunit/banksampletests/accounttest. CS: Line 17"

This is the expected result, because we have not implemented the transferfunds () method. Now let's fix it. Don't close the GUI, go back to your ide and modify the code so that your transferfunds () method looks like this:

Public void transferfunds (Account destination, float amount ){
Destination. Deposit (amount );
Withdraw (amount );
}

Now recompile your code and click the run button again in the GUI-the status bar and the number of nodes become green. (Note that the GUI will automatically reload the Assembly for you; we can continue to work in the IDE and write more tests with the GUI on ).

Let's add some error detection for our account code. Add a minimum balance limit for your account to maintain its continuous operation through your minimum overdraft protection fee. First, we will add a minimum balance protection attribute for the Account class:

Private float minimumbalance = 10.00f;

Public float minimumbalance {
Get {
Return minimumbalance;
}
}

We use an exception to indicate overdraft:

Namespace bank {
Using system;

Public class insufficientfundsexception: applicationexception {
}
}

Add a new method to our accounttest class:

[Test]
[Expectedexception (typeof (insufficientfundsexception)]
Public void transferwithinsufficientfunds (){
Account source = new account ();
Source. Deposit (200.00f );
Account destination = new account ();
Destination. Deposit (150.00f );
Source. transferfunds (destination, 300.00f );
}

In addition to the [test] feature, this test method is associated with an [expectedexception] feature. This indicates that the test code wishes to throw an exception of the specified type; if such an exception is not thrown during execution, the test will fail. Compile your code and return to the GUI. Since you have compiled your test code, the GUI becomes grayed out and restructured the test tree, as if this test has not been run (the GUI can monitor changes to the test assembly, and update when the test tree structure changes. For example, a new test is added ). Click the "run" button-we get a red status bar again. The following error message is displayed: "transferwithinsufficentfunds: insufficientfundsexception was expected ". Let's modify the account code again, and modify the transferfunds () method as follows:

Public void transferfunds (Account destination, float amount ){
Destination. Deposit (amount );

If (balance-amount <minimumbalance)
Throw new insufficientfundsexception ();

Withdraw (amount );
}

Compile and run the test -- green. Successful! But wait. Look at the code we just wrote. We will find that the Bank has lost money in every unsuccessful transfer operation. Let's write a test to confirm our guess. Add this test method:

[Test]
Public void transferwithinsufficientfundsatomicity (){
Account source = new account ();
Source. Deposit (200.00f );
Account destination = new account ();
Destination. Deposit (150.00f );

Try {
Source. transferfunds (destination, 300.00f );
}
Catch (insufficientfundsexception expected ){
}

Assert. areequal (200.00f, source. Balance );
Assert. areequal (150.00f, destination. Balance );
}

We tested the transaction attribute of the method-whether all operations are successful. Compile and run -- red bars. Yes, we lost 300 yuan for no reason-the source account has a correct balance of 150.00, but the destination account shows: $450.00. How can we modify it? Can we only put the call to the minimum balance check before the data update:

Public void transferfunds (Account destination, float amount ){
If (balance-amount <minimumbalance ){
Throw new insufficientfundsexception ();
}
Destination. Deposit (amount );
Withdraw (amount );
}

What if the withdraw () method throws another exception? Should we execute a remedy in the catch block or rely on our transaction manager to reload the object status? Sometimes we have to answer this question, but not now. But how can we handle this failed test now-delete it? A good method is to temporarily ignore it and add the following features to your test method:

[Test]
[Ignore ("need to decide how to implement Transaction Management in the application")]
Public void transferwithinsufficientfundsatomicity (){
// Code is the same
}

Compile and run -- yellow bars. Click the "test not run" tab, and you will see the bank. accounttest. transferwithinsufficientfundsatomicity () together with the reason for the test being ignored in the list.

Let's look at our test code. We can see some suitable refactoring. All methods share a set of common test objects. Let's put the initialization code in a setup method and reuse them in all tests. The refactoring version of our test class is as follows:

Namespace bank {
Using system;
Using nunit. Framework;

[Testfixture]
Public class accounttest {
Account source;
Account destination;

[Setup]
Public void Init (){
Source = new account ();
Source. Deposit (200.00f );
Destination = new account ();
Destination. Deposit (150.00f );
}

[Test]
Public void transferfunds (){
Source. transferfunds (destination, 100.00f );

Assert. areequal (250.00f, destination. Balance );
Assert. areequal (100.00f, source. Balance );
}

[Test]
[Expectedexception (typeof (insufficientfundsexception)]
Public void transferwithinsufficientfunds (){
Source. transferfunds (destination, 300.00f );
}

[Test,
Ignore (
"Need to decide how to implement Transaction Management in the application"
)]
Public void transferwithinsufficientfundsatomicity (){
Try {
Source. transferfunds (destination, 300.00f );
}
Catch (insufficientfundsexception expected ){
}

Assert. areequal (200.00f, source. Balance );
Assert. areequal (150.00f, destination. Balance );
}
}
}

Note that this initialization method has a common initialization Code. Its return value type is void, which has no parameters and is marked by the [setup] feature. Compile and run -- the same yellow bars!

============= Full-text completion ================

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.