----------------------------------------------------
In the previous tutorial http://www.dreaminco...topic108976.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:
[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;
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)
[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:

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

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;
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.
[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:
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.
[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.




MultiQuote




|