Tdd – Extending Assert to support images

While coding and refactoring my current project we found ourselves mocking such type of code:

   1: public class MapPrints
   2: {
   3:     protected string ImagesToReadPath = @"C:\ShaniData\Projects2008\TddSamples\data\";
   4:     protected string ImagesToWritePath = @"C:\ShaniData\Projects2008\TddSamples\output\";
   5:     protected Font DefaultFont = new Font("Arial", 100.0f);
   6:  
   7:     public void Print()
   8:     {
   9:         Bitmap bitmapImage = new Bitmap(3000,3000, PixelFormat.Format32bppArgb);
  10:  
  11:         using (Graphics g = Graphics.FromImage(bitmapImage))
  12:         {
  13:             g.FillRectangle(new SolidBrush(Color.Red), new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height));
  14:             g.DrawString("Gello Graphics World", DefaultFont,  Brushes.White, 100, 100);
  15:             SaveToFile(bitmapImage);            
  16:         }
  17:     }
  18:  
  19:     private void SaveToFile(Bitmap bitmapImage)
  20:     {
  21:         string outputImage = Path.Combine(ImagesToWritePath, "RhinoDiagram.png");
  22:         //Bitmap b = new Bitmap(3000,3000, g);
  23:         bitmapImage.Save(outputImage);
  24:     }
  25: }

The MapPrints class is a sample I just wrote at home to demonstrate the one of the usages for Graphics class in the Print method in our applications.
In this sample we save the image to an output file, but there are places that we just render this to the screen or printer etc.

I might add at this point that I prefer Asserting than mocking as a general idea.
I think that mocking such code is useless. Moreover, we are using a geographic-API which produce use and produce images everywhere, so I decided to extend the images testing capabilities.

I thought how would I like to test this and spike a little bit last weekend and got this bunch of tests:

   1: [TestMethod]
   2: public void CompareImagesSize()
   3: {
   4:     Image expected = Bitmap.FromFile(@"C:\ShaniData\Projects2008\TddSamples\Output\ExpectedImage.png");
   5:     Image actual = Bitmap.FromFile(@"C:\ShaniData\Projects2008\TddSamples\Output\RhinoDiagram.png");
   6:  
   7:     Bitmap expectedBitmap = new Bitmap(expected);
   8:     Bitmap actualBitmap = new Bitmap(actual);
   9:  
  10:     ImageAssert.HasTheSameSize(expectedBitmap, actualBitmap);
  11: }
  12:  
  13: [TestMethod]
  14: public void CompareTwoSameImagesButWithDifferenExtension()
  15: {
  16:     Image expected = Bitmap.FromFile(@"C:\ShaniData\Projects2008\TddSamples\Output\Image2.png");
  17:     Image actual = Bitmap.FromFile(@"C:\ShaniData\Projects2008\TddSamples\Output\Image1.jpg");
  18:  
  19:     Bitmap expectedBitmap = new Bitmap(expected);
  20:     Bitmap actualBitmap = new Bitmap(actual);
  21:  
  22:     ImageAssert.AreEqual(expectedBitmap, actualBitmap);
  23: }

Lines 10, 22: are using the new API: ImageAssert with its new methods: HasTheSameSize and AreEqual.
In such way I can take any two images (from some print code I just wrote in my application) and test it against the expected one.
You can also think about methods returning Images or bitmaps. For me it is just what I’ve needed

After finish spiking I start implementing my dreams, and it is also pretty simple:

   1: public class ImageAssert
   2: {
   3:     //public static void MoreMethods(Bitmap expected, Bitmap actual)
   4:     //{
   5:     //    //Compare image extensions
   6:     //    //Compare Thumbnail...
   7:     //}
   8:  
   9:     public static void HasTheSameSize(Bitmap expected, Bitmap actual)
  10:     {
  11:         if ((expected.Height != actual.Height)
  12:             || (expected.Width != actual.Width))
  13:             HandleFail("ImageAssert.HasTheSameSize", String.Empty);
  14:     }
  15:  
  16:     public static void AreEqual(Bitmap expected, Bitmap actual)
  17:     {
  18:         for (int i = 0; i < expected.Width; i++)
  19:         {
  20:             for (int j = 0; j < expected.Height; j++)
  21:             {
  22:                 Color expectedBit = expected.GetPixel(i, j);
  23:                 Color actualBit = actual.GetPixel(i, j);
  24:                 if (!expectedBit.Equals(actualBit))
  25:                 {
  26:                     HandleFail("ImageAssert.AreEqual", String.Empty, i, j);
  27:                     return;
  28:                 }
  29:             }
  30:         }
  31:     }
  32:  
  33:     internal static void HandleFail(string assertionName, string message, params object[] parameters)
  34:     {
  35:         throw new AssertFailedException(String.Format(assertionName));
  36:     }
  37: }

Lines 9-14: HasTheSameSize method: is only comparing between two images and checking that they are the same size
Lines 16-31: AreEqual method: is running over all pixels of both bitmaps and comparing between them.
Lines 33-37: HandleFail method: we must understand the pattern of Assert – while valid asserts do nothing, on the other side, failures should throw new AssertFailedException()
such exception will be published to the relevant framework. as a red bar.

What next?

  • I would be glad to get some feedback about the new ImageAssert class
  • Let me know what ways do you think we can extend this class
  • Any other thoughts will be appreciated too…
 

Shani Raba

Juggling between Performance Optimization, Agile Training, Continuous Delivery, Get Things Done. Role: Group Leader. Moto: Love your coders.