Database testing with Mono and NUnit

In these days I’m trying to rewrite an old application using Mono.
I’m currently a newbie about Mono and the .Net world, but I happily noticed that the Mono environment come with a bundled interface to NUnit, so I can keep on writing tests as I’m slowly but steadily getting used to.
After having put together a bunch of classes and relative and unit tests, it was time to write the first integration test. I needed to put the development database in a known state before running the test, so I came up with the following class, that I’d like to share with you.

  1. using System;
  2. using System.Collections;
  3. using NUnit.Framework;
  4. using System.IO;
  5. using System.Data;
  6. using System.Data.SqlClient;
  7. namespace TellItMailer{
  8.  public class TestDbSetup{
  9.   public void SetUpDbForTest(object test){
  10.    String path = test.GetType().FullName + ".sql";
  11.    path = path.Replace(this.GetType().Namespace + ".", "");
  12.    path = "/home/danidemi/workspace/TellItMailer/Tests/" + path;
  13.    //Read the script
  14.    String script = "";
  15.    using (StreamReader sr = File.OpenText(path)){
  16.     string s = "";
  17.                while ((s = sr.ReadLine()) != null){
  18.      script = script + s;
  19.                }
  20.           }
  21.  
  22.    string connectionString =
  23.     "Server=192.168.75.128\\SQLEXPRESS;" +
  24.     "Database=TellIt_test;" +
  25.              "User ID=user;" +
  26.              "Password=password;";
  27.  
  28.           IDbConnection dbcon;
  29.    using(dbcon = new SqlConnection(connectionString)){
  30.     dbcon.Open();
  31.            using (IDbCommand dbcmd = dbcon.CreateCommand()) {
  32.                dbcmd.CommandText = script;
  33.      dbcmd.ExecuteNonQuery();
  34.     }
  35.    }
  36.   }
  37.  
  38.  }
  39. }

It’s quite useful. Essentially this class loads a SQL script file whose name is the same of the test class, and execute it.
In this way you have for example a TestFeature.cs file alongside a TestFeature.sql file. Nice if your IDE shows files sorted alphabetically.
I found that the best place to use the class is inside the SetUp marked method. In this way the SQL script is run before each test. Doing it in a local development environment is not so bad, since the scripts are executed at high speed.

So, this is an example of how a test that uses TestDbSetup looks like.

  1. using System;
  2. using NUnit.Framework;
  3. using log4net;
  4. using log4net.Config;
  5. namespace TellItMailer {
  6.  [TestFixture()]
  7.  public class IntegrationTest {
  8.   [SetUp]
  9.   public void SetUp(){
  10.    new TestDbSetup().SetUpDbForTest(this);
  11.   }
  12.  
  13.   [Test]
  14.   public void TestCase(){
  15.    BasicConfigurator.Configure();
  16.   }
  17.  }
  18. }

Pretty useful, IMHO.

Rails ans SQLite3 on Ubuntu

To configure a Rails application in order to use SQLite3 please follow the following steps:

sudo apt-get install  sqlite3 swig libsqlite3-ruby libsqlite3-dev
 sudo gem install sqlite3-ruby

Then create a Rails application as usual and update the environment.rb file in the following way

Rails::Initializer.run do |config|
...
config.gem 'sqlite3-ruby', :lib => "sqlite3"
...
end

Affidabilità dei sistemi informatici bancari

Stavo lavorando in una banca ad un porting verso tecnologie attuali di un sistema esistente da qualche anno. Nell’ambito di tale progetto dovevo realizzare un modulo del sistema il cui compito era sostanzialmente quello di estrarre da DB dei record con un campo data maggiore o uguale alla data di odierna, eseguire alcune elaborazioni e scriverli in un file da inviare ad un sistema a valle per una successiva elaborazione.

Il campo che conteneva la data era un campo CHAR di 8 caratteri e ci era stato assicurato che tutte le date erano nel formato YYYYMMDD. In questo modo per selezionare i record con una data maggiore di quella odierna si poteva sruttare l’ordinamento alfabetico e ad esempio scrivere una condizione del tipo

data >= '20052310'

Facendo qualche test mi sono però accorto che in realtà nel db c’erano record con date nel formato DD/MM/YY. La condizione restituiva perciò anche record con valori pari ad esempio a “23/12/98″, “20/10/89″ ed in generale qualsiasi data il cui giorno fosse maggiore o uguale a 20. Questo perchè, in ordine strettamente alfabetico, “23/12/98″ segue “20052310″. I record che avrebbero dovuto essere stati estratti erano qualche decina, invece la presenza delle date nel formato inatteso, ne faceva salire il numero a qualche centinaio.

Dopo un consulto con un programmatore che lavorava alla manutenzione del sistema decidemmo di lasciare i dati scorretti sul DB ma eliminarli nella query di selezione. E quindi in dettaglio la condizione diventò…

data >= '20052310' AND data not like '__/__/__'

Tutto sembrava andare per il meglio, il file contenente i risultati divenne molto più corto e l’elaborazione successiva ne avrebbe certamente giovato.

Mi pareva comunque strano come per i sette o otto anni precedenti il sistema a valle avesse elaborato ogni giorno centinaia di record inutili senza che sollevare il minimo problema.

In fase di test un file campione genenrato dal nuovo sistema doveva essere caricato dal sistema successivo. Il giorno del test ricevetti una telefonata ed il tecnico all’altro capo del filo mi disse che il test era fallito poichè alcuni record contenuti nel file non trovano riscontro nei dati di altre tabelle. Pronto ad affrontare una noiosissima sessione di debug mi accorsi che nel file prodotto non trovavo minimamente traccia dei record errati a cui si era riferito il tecnico.

Dopo una ricerca trovai i record incriminati nel file che era stato prodotto non dal nostro nuovo sistema ma dal vecchio sistema correntemente in produzione. Insomma, per una svista, il tecnico aveva sottoposto a test non il file prodotto dal nuovo sistema, ma quello prodotto quotidianamente, ormai da anni, dal sistema in produzione. E ci aveva trovato pure degli errori!