WatiN, looking for content in GridView

Quite often I need to automate test page and check that the contents of a GridView contains exactly some strings. First of all I have an helper class that helps me to cope with the name that asp.net give to controls contained in another controls, then I write some helper methods to assert that the content of a grid is what I expected to be.

      public static void TableContentEqAssertion(IE ie, String tableName, Int32 row, Int32 col, String expectedvalue) {
         NUnit.Framework.
Assert.AreEqual(
            expectedvalue, 
            ie.Table(
AspControlFinder.FindById(tableName)).TableRows[row].TableCells[col].InnerHtml );
      }

This simple function accepts the IE entity used to check the table, then the row and column of the table and finally the expected value. I simply call this function in this way.

Helpers.TableContentEqAssertion(ie, “GridEsperienze”, 1, 1, “–“);

Simple and concise. But this is not enough, 99% of the times I need to make test and verify that the whole content of the table will contains expected test, with the above function I need to do code like this.

Helpers.TableContentEqAssertion(ie, “GridEsperienze”, 1, 1, “–“);
Helpers.TableContentEqAssertion(ie, “GridEsperienze”, 1, 2, “Segretario Ricevimento”);
Helpers.TableContentEqAssertion(ie, “GridEsperienze”, 1, 3, “aziendaaaaaaaaaaa”);
Helpers.TableContentEqAssertion(ie, “GridEsperienze”, 1, 4, “segretariato”);

This is not exiting L, so I decided to create another function,

      public static void TableContentEqAssertion(
         
IE ie,
         
String tableName,
         
Int32 startingrow,
         
params String[] expectedvalue) {
 
         WatiN.Core.
Table t = ie.Table(AspControlFinder.FindById(tableName));
         
Int32 numOfColumn = t.TableRows[startingrow].TableCells.Length;
         
Int32 curRow = startingrow;
         
Int32 curColumn = 0;
         
foreach (String expected in expectedvalue) {
            
if (expected != null )
               NUnit.Framework.
Assert.AreEqual(expected, t.TableRows[curRow].TableCells[curColumn].InnerHtml);
            
if (++curColumn >= numOfColumn) {
               curColumn = 0;
               curRow++;
            }
         }
      }

This is far better, this function accepts the IE instance, the name of the grid, the starting row (usually 1 to avoid the header) and then a variable number of string arguments. Internally the function simply scan table cells one after another and does an assertion for each not null value in the expectedValue array. For example, in a test I have to verify content of a gridview with 8 column, 2 row + the header and the last three columns contain buttons for Create New, Delete and edit operation and should not be tested. I create the following test.

   Helpers.TableContentEqAssertion(ie, “GridEsperienze”, 1, 
            
“06/1991”,“–“, “Segretario Ricevimento”,“aziendaaaaaaaaaaa”,“segretariato”,
            
null, null, null, “06/1959”, “06/1991”, “Satinatore di metalli”, “la mia azienda”, “Satinatore professionista completo”);

This is a more readable test.

Alk.

A pattern to access DB with IDataReader

Some days ago I posted about an helper class to easy the access to database. I took original code by ayende and do slightly modifications to make database indipendent. A natural extension to that class is the ability to retrieve a datareader with some data. An initial solution is simply call the core Execute() function with this code.

         Nablasoft.Helpers.DataAccess.Execute(
            
delegate(DbCommand command, DbProviderFactory factory) {
               command.CommandType = System.Data.
CommandType.Text;
               command.CommandText = 
“SELECT CompanyName FROM Customers WHERE CustomerId = @id”;
               Nablasoft.Helpers.
DataAccess.AddParameterToCommand(
                  command, factory, System.Data.
DbType.String, “id”, “ANATR”);
               
//now access the datareader.
               
using(IDataReader dr = command.ExecuteReader()) {
                  
Assert.IsTrue(dr.Read()); //Check if the datareader contains data.
                  
Assert.AreEqual(“Ana Trujillo Emparedados y helados”, (String)dr[“CompanyName”]);
               }
            });

The code simply creates a delegate that prepares the command, and then retrieves a IDataReader with ExecuteReader(). The code above was easy to read but it has a problem, if the caller forget to dispose the IDataReader object a connection leak will show up. In past experiences I found that dealing with connection leaks, especially in web application can be a nightmare, so I’d like to wrap the creation of DataReader in a way that permits to the caller not worry about disposing any resource he uses. This poses a problem, actually the template pattern work with this sequences of operations

1) Create the connection and a transaction
2) Create the command and enlist in the current transaction
3) Call the delegates passed by the caller, the delegates prepare the command and does something with it
4) Using clause dispose command, connection and check for exeption to rollback transaction.

I should modify the pattern of the template, point 3 should be splitted

3a) call the delegate passed by the caller, this delegate prepare the command
3b) call ExecuteDataReader() on prepared command
3c) Call another delegate that access IDataReader object
3d) Dispose the IDataReader.

This pattern forced the caller to create two anonymous delegates, one to prepare the command, and the other to access the IDataReader, this makes the code less readable. A better solution is to create an helper function like this

    1    public static void ExecuteReader(
    2          VoidFunc<DbCommand, DbProviderFactory, Func<IDataReader>> commandPrepareFunction) {
    3 
    4          Execute(delegate(DbCommand command, DbProviderFactory factory) {
    5             //The code to execute only assures that the eventually created datareader would be
    6             //closed in a finally block.
    7             IDataReader dr = null;
    8             try {
    9                commandPrepareFunction(command, factory,
   10                                    delegate() {
   11                                       dr = command.ExecuteReader();
   12                                       return dr;
   13                                    });
   14             }
   15             finally {
   16                if (dr != null) dr.Dispose();
   17             }
   18          });
   19       }

This function accepts a delegate with three arguments, the first is the command to retrieve data, second parameter is DbFactory class to create parameters for the command and at last we have another delegate function with no parameter that returns a IDataReader. This function creates an anonymous delegate at line 4, the body of the delegate simply call the caller supplied delegate (line 9) and creates another anonymous delegate for the third parameter, the function is called with a try-finally block to ensure that the datareader will be disposed. The trick is that the creation of the IDAtaReader object now is moved to the infrastructure code, so I can dispose it. Let’s look at how the caller can use this helper function to access data.

      [Test]
      
public void TestDbHelperDataReader() {
         Nablasoft.Helpers.
DataAccess.ExecuteReader(
            
delegate(DbCommand command, DbProviderFactory factory, Func<IDataReader> getDatareader) {
               
//First prepare the command
               command.CommandType = System.Data.
CommandType.Text;
               command.CommandText = 
“SELECT CompanyName FROM Customers WHERE CustomerId = @id”;
               Nablasoft.Helpers.
DataAccess.AddParameterToCommand(
                  command, factory, System.Data.
DbType.String, “id”, “ANATR”);
               
//now access the datareader.
               
IDataReader dr = getDatareader();
               
Assert.IsTrue(dr.Read()); //Check if the datareader contains data.
               
Assert.AreEqual(“Ana Trujillo Emparedados y helados”, (String) dr[“CompanyName”]);
            });
      }

As you can see the code is really simple and straightforward. The caller first prepares the command, and then once the command is ready to be executed it calls the getDatareader() delegate passed as argument to obtain a datareader for accessing data. What I like of this pattern is that the caller do not have the burden to close the IDataReader because this is done in the infrastructure function. Code with a lot of using or try-finally blocks is less readable, and moreover an inexperienced programmer could forget to dispose a datareader. With this pattern the caller should only prepare the DbCommand and access the DataReader, no using, no try catch, no way to make a leak. With this pattern we can also make an helper class to work with DataSets.

      public static void ExecuteDataset(
         
VoidFunc<DbCommand, DbProviderFactory, Func<DataSet>> commandPrepareFunction) {
 
         Execute(
delegate(DbCommand command, DbProviderFactory factory) {
            
//The code to execute only assures that the eventually created datareader would be
            
//closed in a finally block.
            
using (DataSet ds = new DataSet()) {
               commandPrepareFunction(command, factory,
                                   
delegate() {
                                      
using (DbDataAdapter da = factory.CreateDataAdapter()) {
                                         da.SelectCommand = command;
                                         da.Fill(ds);
                                      }
                                      
return ds;
                                   });
            }
 
         });
      }

This function is a copy of the previous one, it simply uses the command prepared by the caller to insert as selectCommand for a DataAdapter and fill a dataset. The using clauses are needed to be sure that everything is diposed correctly. Here is how you can retrieve data

            delegate(DbCommand command, DbProviderFactory factory, Func<DataSet> getDataSet) {
               command.CommandText = 
“SELECT * FROM Customers”;
               
DataSet Result = getDataSet();
               
Assert.AreEqual(1, Result.Tables.Count);
               
Assert.AreNotEqual(0, Result.Tables[0].Rows.Count);
            });

Again the caller has not the burden of dispose anything. If you like this you can access code here.

Alk.

Standard configuration for .net 2.0

I’m trying to develop a little framework to include in future projects, actually I had classes and project spread around partition D F and G, and I realized that I’m not really a tidy person :D. At this moment I only had written some classes to handle access to db with direct Sql, and I really liked used Anonymous delegate as did ayende in one of his post. At a certain point I faced the problem to decide where to save the setting of the project, for example the main connectionString. I must admit that I really love the XML configuration of .Net, so instead of using plain application setting I plan to use a custom configuration. I started with a simple class to handle global section of the configuration.

public class NablaHelpersConfiguration : ConfigurationSection {
 
   [
ConfigurationProperty(“DataAccessConfiguration”, IsRequired = true)]
   
public DataAccessConfiguration DataAccess {
      
get {
         
return (DataAccessConfiguration)this[“DataAccessConfiguration”];
      }
   }
}

This is the base class for the configuration, and right now it contains only a property that is an instance of the class that handle the configuration of the DataAccess part of the library. As you can see with ConfigurationProperty attribute I specify that my configuration has an element called DataAccessConfiguration of type DataAccessConfiguration, the class inherits from ConfigurationSection
because it is my config section for the library. Now it’s the turn of DataAccessConfigurationClass

public class DataAccessConfiguration : ConfigurationElement {
 
   [
ConfigurationProperty(“MainConnectionString”)]
   
public ConnectionStringSettings ConnectionString {
      
get { return (ConnectionStringSettings)this[“MainConnectionString”]; }
      
set { this[“MainConnectionString”] = value; }
   }
}

This class inherits from ConfigurationElement and has a simple property marked with ConfigurationPropertyAttribute that states that my data access layer need an element called MainConnectionString of type ConnectionStringSettings, the standard class to store connection strings in .net. With these two classes I can simply create this app.config file.

 <configSections>
      <section 
name=NablaHelpers 
type=Nablasoft.Helpers.Configuration.NablaHelpersConfiguration, NablaHelpers/>
   </configSections>
 
   <!–Configuration for the nablahelper assembly–>
   <NablaHelpers>
      <DataAccessConfiguration>
         <MainConnectionString
                  name=MainConnectionString
                  connectionString=Database=Northwind;Server=localhost\SQL2000;… “
                  providerName=System.Data.SqlClient/>
      </DataAccessConfiguration>
   </NablaHelpers>

Â

To use my custom configuration classes I firt specify in configSection the type of the configuration class (NablaHelpersConfiguration) as well as the node name that contains data for the configuration, then I create the section and name it “NablaHelpers”, and inside I store all my configuration. I must admit that I really love XML configuration files.
To retrieve current configuration in the code you can simply ask to the System.Configuration class.

NablaHelpersConfiguration IConfigurationHandler.CurrentConfiguration {
   
get {
      
return (NablaHelpersConfiguration) System.Configuration
           .
ConfigurationManager.GetSection(“NablaHelpers”);
   }
} 
Â

I include this property in an helper class to avoid to call System.Configuration each time, as you can see an instance of the configuration class can be obtained simply calling System.Configuration.ConfigurationManager.GetSection() specifying the name of the section to retrieve. With custom configuration classes you can include all your configuration in a single customized section of your config file.

Alk.

Â

Â

Falling in love with a ghost :D

After a long time that some friends told me about boo language, finally yesterday I downloaded the trunk and began to familiarize with the language. The first thing that surprised me is the ability to break into debugger with simple instruction like these

import System.Diagnostics

Debug.Fail(“”)

And your favorite debugger will show up with full support for intellisense, step and so on, I’m very pleased with this.

Alk.