C# School Assignment? Project Due Tomorrow? Chat LIVE With A Programming Expert!

Welcome to Dream.In.Code
Become a C# Expert!

Join 307,146 C# Programmers for FREE! Get instant access to thousands of C# experts, tutorials, code snippets, and more! There are 1,729 people online right now. Registration is fast and FREE... Join Now!




C# Unit Testing Basics Part 2

 
Reply to this topicStart new topic

> C# Unit Testing Basics Part 2, A second look at unit testing, with a couple more techniques

SwiftStriker00
Group Icon



post 19 Jun, 2009 - 05:52 AM
Post #1


C# Unit Testing Basics Part II Return of the Asserts
----------------------------------------------------

In the previous tutorial http://www.dreamincode.net/forums/showtopic108976.htm I introduced the concepts of a TestMethod, and the Assert methods. This tutorial will elaborate more on ExpectedExceptions and some tricks we will use with try/catch, and using a database to our advantage.

Expected Exceptions
Remember that when we create an expected exception like so, for a our test method:
CODE

[TestMethod, ExpectedException(  typeof( ArgumentNullException ) )]
public void Test_nullArguments(){
    ///Code
}

Also remember that the Test will Pass if the exception is thrown.

It is a good idea to test all exceptions thrown by methods, because if the code was developed to throw them, there was an important reason to do so. For example lets take a login manager, some hypothetical exceptions we could have are: ArgumentNullException, AccountNotFoundException, InvalidPasswordException, ServerConnectionException

Testing a Login System
so lets take a test class and test ArgumentNullException, AccountNotFoundException, InvalidPasswordException, ServerConnectionException;
CODE

namespace Connection {
    [TestClass]
    public  class Test_ConnectionManager {
    
        ConnectionManager manager;     //Connects client to login system
        User user;                     // A user taht has a Username and Password associated with it
        string name, pass;
        string ip;
        int port;
        
        [TestInitialize]
        public void initTests(){
            ip = "192.168.0.12"; //Yes i know its local ip, but its not real anyway
            port = 23;
            
            // defaults ip and port to local host and 22 respectively
            manager = new ConnectionManager();
            
            name = "DICHead123";
            pass = "interwebz";
            user = new User( name, pass );
            
            manager.register( user ); //Adds the user to server database to verify login
        }
        
        [TestCleanUp]
        public void cleanupTests(){
            manager.logout( user );
            manager.disconnect();
        }
        
        [TestMethod, ExpectedException( typeof( ArguementNullException))]
        public void Test_Null_Login(){
            manager.Login( user.UserName, null ); //Breaks here
        }
    }
}

Ok so thats a pretty simple setup, every test we are going to run, we will create a new manager and user to test with. and at the end will force the logout and disconnect to make sure everything shuts down. and we have a simple test. Now lets say that we only want broad test reports to print out to our boss. He doesn't care about every single Assert and/or Test, just: does login work yes or no(and why)?. Or you just want to compress things, how can we do this? Try/Catch! (I will assume you know the basics of the Try/Catch Block)

CODE

[TestMethod]
public void Login_Test_Result() {
    //Nice official name for your boss to see on the printout
    
    User bad = new User( "registration", "refusal");
    
    ///Check for failure cases first
    
    //Test for server connection
    try{
        manager.connectTo( "0.0.0.0", 22 );
        Assert.Fail("Issue: Manager connected to bad server address and port");
    } catch( ServerConnectionException sce ){
        //Notice I dont do anything with the catch? Because I want it to happen...
        //Also notice I dont catch Exception. Why? because then the Assert.Fail()
        //would not report anything
    } finally {
        //I know this will work since I hard coded it, so I can just make sure its
        //connected properly for the rest of the test
        manager.connectTo( ip, port );
    }
    
    //Test no registration
    try{
        manager.Login( bad );
        Assert.Fail("Issue: The connection manager accepts non-registerd user accounts");
    } catch( AccountNotFoundException anfe ){ }
    
    //Test Registered with bad Pass
    try{
        manager.Login( user.Username, bad.Pass);
        Assert.Fail( "Error: Login was successful with wrong password" );
    }catch( InvalidPasswordException ){ }
    
    //Now that all failure cases have been checked, we do a successful test:
    
    try{
        manager.Login( user.UserName, user.Pass );
    } catch( Exception e ){
        //I normally just catch this in the fluke chance that something else that could
        //go wrong. and since I rerpot the exception catch with the assert, I can go back
        //Later and add more tests
        Assert.Fail( "Unknown Failure: " + e.Message );
    }    


And with luck we get this:
IPB Image

Sql Database

Lets say we were logging some data about DIC. Well lets use this sample table to test with

dbo.UserAccountTable
IPB Image
Were also going to assume that each row is an UserAccount, with each piece of data being a public
get/set Property. So we can work with the data in our code.
We have a DataManager that has the following methods:

public UserAccount Get( string username);
public void Add( UserAccount u );
public bool Delete( string username );
public void Modify( string username , string variable_to_mod, string_newValue);

We need to test their functionality;

CODE

using System.Data;
using System.Data.Linq;
using System.Data.SqlClient;

namespace DatabaseProject{
    [TestClass]
    public class TestDataManager{
    
        public SqlConnection conn;
        public SqlDataAdapter adpt;
        public SqlCommand cmdSelect_tbl;
        public DataTable expectedData;
        
        DataManager manager;
        
        [TestInit]
        public void initTests(){
            conn = new SqlConnection("Data Source=.\\SQLEXPRESS;Initial Catalog=DICDatabase;User ID=admin; Password=admin;Integrated Security=true");
            conn.Open();
            adpt = new SqlDataAdapter();
            manager = new DataManager( "dicDatabase" ); //Just connects to our mock database
        }
        
        [TestCleanUp]
        public void cleanTests(){
            conn.Close();
        }
        
        ///<summary>
        ///Utility method to generate a data table from sql select command
        ///</summar>
        public DataTable select_DataTable( string columnName, string value ){
            cmdSelect_tblTest = new SqlCommand("select * from dbo.UserAccountTable where " + columnName + "='" + value + "'", conn);
            DataTable tempTable = new DataTable(theTable);
            adpt.SelectCommand = cmdSelect_tblTest;
            adpt.Fill(tempTable);
            return tempTable;
        }
    }
}


I have included select_dataTable method as a quick utility to return a table from the sql select command, from a given set of parameters. For example select_DataTable( "isBanned", "False" ) will return DICHead123, skyhawk133 and swiftstriker00 in a DataTable.

Now lets take a look at public UserAccount Get( string username);. to get the UserAccount object for skyhawk133, would be simple. But lets see how we actually compare the expected to the actual objects.
CODE

[TestMethod]
public void Test_Get_UA(){
    
    string account = "skyhawk133";
    
    //Heres the data that we are testing
    UserAccount actual = DataManager.Get( account );
    
    //We are going to check to see if it actually retrived the database info properly
    DataTable expected = select_DataTable( "UserName", account );
    
    //But UserAccount and DataTables aren't comparable objects so we need to pull the data individually
    Assert.AreEqual( expected.Rows[0]["UserName"], actual.UserName, "I hope the usernames are the same");
    Assert.AreEqual( expected.Rows[0]["Password"], actual.Pass, "Passwords dont match");
    Assert.AerEqual( (int)expected.Rows[0]["PostCount"], actual.Posts, "Number of posts dont match");
    Assert.AerEqual( (int)expected.Rows[0]["Kudos"], actual.Kudos "Kudos are not the same");
    Assert.AerEqual( (bool)expected.Rows[0]["isBanned"], actual.Banned, "Ban hammer was not swung propperly");
}

Now i hate re-writing Asserts over and over again, so lets make a helper method to save us an effort:
CODE

public void Assert_Clauses( DataTable expected, UserAccount actual){
    Assert.AreEqual( expected.Rows[0]["UserName"], actual.UserName, "I hope the usernames are the same");
    Assert.AreEqual( expected.Rows[0]["Password"], actual.Pass, "Passwords dont match");
    Assert.AerEqual( (int)expected.Rows[0]["PostCount"], actual.Posts, "Number of posts dont match");
    Assert.AerEqual( (int)expected.Rows[0]["Kudos"], actual.Kudos "Kudos are not the same");
    Assert.AerEqual( (bool)expected.Rows[0]["isBanned"], actual.Banned, "Ban hammer was not swung propperly");
}


Now it will be easy to test Add. We will just create a UserAccount and add it to the database.
CODE

[TestMethod]
public void Test_Add_UA(){
    Useracount ua = new UserAccount( "Martyr2", "lotr", 6638, 9001, false );
    DataManager.Add( ua );
    //Now that it should be in. Compare all the data
    this.Assert_Clauses( select_Datatable( "UserName", ua.UserName ), ua );
}


Can you think of ways that Modify and Delete might be tested in this manner. *Hint* you dont even need to check the bool return, or compare any of the variables with DataManager.Delete().

I hope this small addon on to the previous tutorial helped and really got your thought processes motivated. Just remember if your a Software_Test coder, or just need to act as one, its fun because you get to put all of your energy and creativity into trying to break your developer(or friends, or yourself)'s code.



Go to the top of the page
+Quote Post


Register to Make This Ad Go Away!

SmithaMangalore
*



post 6 Jul, 2009 - 11:03 PM
Post #2
Good one...but it is too simple...

Is there any article or link to develop the testing Framework which takes and puts the report to data source which could be anything....
Go to the top of the page
+Quote Post


Fast ReplyReply to this topicStart new topic
2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members:

 


Lo-Fi Version Time is now: 11/21/09 03:51PM

Live C# Help!

Be Social

Dream.In.Code RSS Feed Dream.In.Code LinkedIn Group Follow Us On Twitter Fan Us On Facebook

C# Tutorials

Reference Sheets

C# Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month