Raba - Defend your code RSS 2.0
# Saturday, August 01, 2009

Test methods must be written as production code.
While writing your tests you must act the same methods you write for your production code which means:

  1. human-readable (code standard, pattern etc.)
  2. code re-use (copy paste is never acceptable)
  3. etc...

This is a code you will probably find in your test projects

   1: [Test]
   2: public void GetCommentsByQuery_LookFormHmmmText_FindAtLeaseOne()
   3: {
   4:     SvnLogParser parser = new SvnLogParser();
   5:     string textToSearch = "Hmmm...";
   6:     var results = parser.GetCommentsByQuery(comment => comment.Contains(textToSearch));
   7:     CollectionAssertExtensions.IsNotEmpty(results);
   8: }
   9:  
  10: [Test]
  11: public void GetCommentsByQuery_LookFormBugText_FindAtLeastOne()
  12: {
  13:     SvnLogParser parser = new SvnLogParser();
  14:     string textToSearch = "bug";
  15:     var results = parser.GetCommentsByQuery(comment => comment.Contains(textToSearch));
  16:     CollectionAssertExtensions.IsNotEmpty(results);
  17: }

You can see that the two methods are pretty much the same, the only change is the textToSearch variable.
There are some excuses for such duplication:

  • "We want two different names... to easily understand the failiure reason"
  • "we want it to be easy to read, without context switches..." (method calls and un-needed inheritance complexity)

We, of course, can refactor this code, like this:

   1: [Test]
   2: public void GetCommentsByQuery_LookFormBugText_FindAtLeastOne()
   3: {
   4:     string textToSearch = "bug";
   5:     GetCommentsByQuery_AssertAllItemsStartsWith(textToSearch);
   6: }
   7:  
   8:  
   9: [Test]
  10: public void GetCommnentsByQuery_LookForHmmmText_VerifyInsideComment()
  11: {
  12:     string textToSearch = "Hmmm...";
  13:     GetCommentsByQuery_AssertAllItemsStartsWith(textToSearch);
  14: }
  15:  
  16: public void GetCommentsByQuery_AssertAllItemsStartsWith(string textToSearch)
  17: {
  18:     SvnLogParser parser = new SvnLogParser();
  19:     var results = parser.GetCommentsByQuery(comment => comment.StartsWith(textToSearch));
  20:  
  21:     CollectionAssertExtensions.AllItemsSatisfy(results, res => res.Comment.StartsWith(textToSearch));
  22: }

This is better when you think of clone detection: less identical rows and the logic was extracted to one method.
But people might say that they can't see the AAA (Arrange, Act, Assert) and they want it in one place,
Moreover, in such code sample, it is harder to find all the input parameters, cause they will be spread all over the TestFixture methods.

 

NUnit 2.5 added TestCaseAttribute, this can help us write tests that are:

  • more readable
  • shorter test-fixture
  • all-in-one-place tests
   1: [TestCase("Hm...")]
   2: [TestCase("bug")]
2: [TestCase("bug")]
   3: public void GetCommentsByQuery_LookForText_FindAtLeastOne(string textToSearch)
   4: {
   5:     SvnLogParser parser = new SvnLogParser();
   6:     var results = parser.GetCommentsByQuery(comment => comment.Contains(textToSearch));
   7:     CollectionAssertExtensions.IsNotEmpty(results);
   8: }

Here you can avoid the duplication and you won't need to refactor your Tests to more than one method, while you still see them running using the given parameter,
for example when the second parameter will fail you will see this output:

------ Test started: Assembly: App.Tests.dll ------

TestCase 'App.Tests.NewFolder1.SvnLogParserTests.GetCommentsByQuery_LookForText_FindAtLeastOne("Hm...")'
failed: 
  Expected: True
  But was:  False
    C:\ShaniData\ProjectsByTitle\Delver\App.Tests\NewFolder1\SvnLogParserTests.cs(75,0): at App.Tests.NewFolder1.CollectionAssertExtensions.IsNotEmpty[T]
    C:\ShaniData\ProjectsByTitle\Delver\App.Tests\NewFolder1\SvnLogParserTests.cs(33,0): at App.Tests.NewFolder1.SvnLogParserTests.GetCommentsByQuery_LookForText_Find...


4 passed, 1 failed, 0 skipped, took 0.78 seconds (NUnit 2.5).


The output will point the given method and the parameter used - which will ease finding the error.
You can extend reading about the usage here

Saturday, August 01, 2009 5:20:12 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2] - Trackback
.Net 3.5 | C#3.0 | TDD | NUnit

# Friday, April 10, 2009

Last month I've presented a simple newbie's tutorial about NTS - Net Topology Suite.
Here you can download the code sample & presentation.

What is it NTS (Net Topology Suite)?

  • implements geometry model defined in OpenGis Consortium (OGC)
  • implements  simple features inside the OpenGis Consortium (OGC) as Geographic Data access
  • implements Some great OGC writers as: GmlWriter (Geographic markup language), WktWriter (Well Known Text)

How do I know whether I need NTS:

  1. You are coding a GIS (Geographic Information Systems) applications
  2. You want to use a known Convention for Point, Polygon, Polyline etc.
  3. You want simple implementation for OGC

3 times No - you don't need this
3 times Yes - you must read this article and probably use it.

You can read more about Kml & C#3.0 - at my last post.
I will keep posting more samples in the near future.

Friday, April 10, 2009 10:15:45 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
.Net 3.5 | C#3.0 | GIS

This post inspired by Gal Ochana.

Gal is a new gifted programmer at my team, she presented a great presentation about Linq to XML - you can download code here.
The great bonus at her presentation was the Linq to Kml Sample, I would like to share this with you.

The kml itself is an XML file at our sample it looks like this:

   1: <?xml version="1.0" encoding="UTF-8"?>
   2: <kml xmlns="http://www.opengis.net/kml/2.2">
   3:     <Placemark>    
   4:         <name continent="America">America</name>    
   5:         <description>Attached to the ground. Intelligently places itself at the height of the underlying terrain.</description>    
   6:         <Point>      
   7:             <coordinates>-100.0822035425683,37.42228990140251,0</coordinates>    
   8:         </Point>  
   9:     </Placemark>
  10:     <Placemark>    
  11:         <name continent="Africa">Africa</name>    
  12:         <description>Attached to the ground. Intelligently places itself at the height of the underlying terrain.</description>    
  13:         <Point>      
  14:             <coordinates>20.0822035425683,20.42228990140251,0</coordinates>    
  15:         </Point>  
  16:     </Placemark>
  17:     <Placemark>    
  18:         <name continent="Asia">Asia</name>    
  19:         <description>Attached to the ground. Intelligently places itself at the height of the underlying terrain.</description>    
  20:         <Point>      
  21:             <coordinates>42.0822035425683,33.42228990140251,0</coordinates>    
  22:         </Point>  
  23:     </Placemark>
  24:     <Placemark>    
  25:         <name continent="Europe">Europe</name>    
  26:         <description>Europe</description>    
  27:         <Point>      
  28:             <coordinates>100.0822035425683,62.42228990140251,0</coordinates>    
  29:         </Point>  
  30:     </Placemark>
  31: </kml>


You can read more about Kml here.


Screen-shot of the above kml in the ArcGis-Explorer:

You can see in the above Kml file sample the continents represented as a simple points, of course you can extend it to include polygons, poly-lines or anything else that valid within KML standard.
The only things that differs Kml from the known Xml file is the namespace that we will need to handle in our code, let's see the query itself:

   1: XNamespace ns = "http://www.opengis.net/kml/2.2"; 
   2:  
   3: XDocument kmlDoc = XDocument.Load(InputKml);
   4:  
   5: var result = from placemark in kmlDoc.Descendants(ns + "Placemark")
   6:              where (placemark.Element(ns + "name")
   7:                              .Attribute("continent").Value == 
   8:                              Continents.SelectedItem.ToString())
   9:              select placemark;

 

line 1: declare the full namespace that will be used for the attributes and Tags
line 3: loading the kml input file
line 5-9: run a simple query to select a single continent, pay attention to the namespace that we concatenate for selecting the right node.

Here you can see a screen-shot with the result of the above query using the "Asia" continent as the selected item.

Enjoy.

Friday, April 10, 2009 10:03:14 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
.Net 3.5 | C#3.0 | LINQ | GIS | AGX

# Sunday, December 21, 2008

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...
Sunday, December 21, 2008 10:57:27 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
C#3.0 | Software Development | TDD

# Monday, April 21, 2008

This is the main day of TechEd were we had lectures from 8:00 till 19:00 Here are my list of lectures for that day:

Optimizing and Extending ASP.NET Ajax - for going beyond the update panel  - (by Assaf Shely)
This was a lecture of 400, at least that is what they wrote. in reality that was an introduction for Ajax, he explain about the update panel and about JSON. The only thing I want to add from this lecture is all he says about ASP.NET Ajax 3.6 - which can support browser history capabilities.
My grade to Assaf's lecture: 6/10 (a big disappointment)

DDC & ASP.NET MVC (by Noam King)
DDC - dynamic data controls (you can read here), MVC - Model View Controller (you can read more in my last post about ASP.NET MVC).
Noam showed a simple usage of the MVC API, and a simple creation of a web site from the DDC API, those both samples are the simple web casts you can find and learn in 15 minutes. a big waste of time (again)
My grade to Noam's lecture: 8/10 (Noam is a great lecturer, the problem was the level of the lecture - All they should do is to write: Intro at the beginning of the lecture description)

Service Host Customization (by Eyal Vardi)
Finally a great lecture for the second day. It was a great one. you can download the lecture here.
Eyal showed a great sample for Config manager - which helps you manage your configurations details (addresses for example) - and in such way you can manage it inside your DB or something else - better than a configuration file (it gave me some great ideas for my next posts).
He also used the ServiceHost VIsualizer - I even started to use it at my place.
Next we dive into the Service Model Layer and its behaviors.

I'll probably write about each of them in the near future.
For now, there were 4 demos:

Demo 1: CD - Channel dispatcher - writing you own Error Handler, we also talk about the throttling.
Demo 2: Saving persistence of the Service inside a given Service Host.
Demo 3: DR - Object Pooling using the Dispatcher Runtime, it is a great sample.
Demo 4: Serialization Issues - Eyal wrote a sample-infrastructure for handling Serialization and DeSerialization without using the known-types.

Go Gold with Silverlight (by Laurence Moroney)

This was an Introduction to Silverlight (of course), the only thing I liked about the lecture is the way he explained the differences between Silverlight 1.0 to Silverlight 2, while Silverlight 1.0 - is web friendly UI the Silverlight 2 - is .net based programming model with improve productivity. Laurence showed some cool samples (most of them you can find here, here, here and here), the one I liked the most is a Server servlet (written using J2EE) but the client that consume it is a .net web client (Silverlight) - at my place, one of our teamd, has some Java assets and they want to use it, so they start develop their own UI like in Java for movies\Audio\Web-Parts\Ajax capabilities - this sample could help them a lot.

My grade to the Laurence lecture is 7/10 - Laurence was great the problem was the lecture agenda - I really had enough from the Silverlight previews (so either call it preview\intro or show some code in it)

Restfulness (by Ron Jacobs)
First you should read this book (as they said - this is all you need to know about REST)
After David Chappell's lecture about REST for the first day people told me not to take another REST-lecture, but I did - and - IT WAS GREAT!.
you can read more on Avi's post. Ron gave more details about the implementation of REST using the WCF. for example:
How do you notify the sender about error in REST, you can't send XML back to the client... The answer is simple: for example for deleting non-existing row you will get 404 (HTTP Error code) - I might admit I like this one, the problem is that you should write your own fault architecture to return those codes back, _still_ not implemented at the REST attributes of the WCF. (one more sample: an internal error in your code will probably should return 500 - un-handled exception)
Here is another thing that is still not so easy to do in your WCF implementation - how you can ask for a response? for example you would like to get the JSON return value and not the simple xml... in REST - all you need to do is to add the extension to your request, but you still need to implement it in the WebMethodAttribute by yourself.
And there were more samples, you can download them here... (Ron's website). {you can also read  more in Wortzel's post}
My grade to Ron's lecture is: 9/10.

Monday, April 21, 2008 2:56:16 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
.Net 3.5 | Asp.net MVC | C#3.0 | LINQ

# Monday, February 11, 2008

I've tried to write a simple code today GetEverythingButTheFirstElement() -> a code that get the all elements but the first one.

of course I've started with the old fashioned way:

   1:  string[] firstOne = new string[args.Count() - 1];
   2:  for (int i = 1; i < args.Count(); i++)
   3:  {
   4:   
   5:      firstOne[i - 1] = args[i];
   6:   
   7:  }

Now I've start refactoring it to something more C#3.0-able and it looks like this one:

   1:  // The method to use as the predicate for the where
   2:  public static bool GetAllElementsButTheFirstOne(string s, int i)
   3:  {
   4:      if (i == 0)
   5:          return false;
   6:   
   7:      return true;
   8:  }
   9:   
  10:  //The usage at my code
  11:  IEnumerable<string> secondTemp = args.Where(GetAllElementsButTheFirstOne);

Here happen something strange, the secondTemp do not hold objects in it, looks strange? no! it uses a lazy load thanks to the Linq defaults, so I've added this line at the end:

   12:  string[] secondOne = secondTemp.ToArray<string>();

So I decided to refactor this code a little bit more, I didn't like the string that the Where() force me to write, so I've added my own Where:

   1:  public static class Extensions
   2:  {
   3:      public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<int, bool> predicate)
   4:    
   5:      {
   6:          for(int i=0; i < source.Count(); i++)
   7:          {
   8:              if (predicate(i))
   9:                 yield return source.ElementAt(i);
  10:          }
  11:      }
  12:  }

This looks awesome now I can write it just like this:

   1:  public static bool GetAllElementsButTheFirstOne(int i)
   2:  {
   3:      if (i == 0)
   4:          return false;
   5:      return true;
   6:  }

But Hey, what do you think about this code?

   1:  IEnumerable<string> thirdTemp = args.Where((int i) => { return i > 0; });

Haaa, now it looks good.

This is not the first time I am writing lambda expression but I still thinking to my self how much I should read&code so this will be my natural way of thinking... for now it take me more time to write it than in the casual way.

Cheers.

Monday, February 11, 2008 11:32:49 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
C#3.0 | LINQ

Following my last post about LINQ, Expression Trees & Lambda Expressions I've found this Linq Quiz:

C# 3.0 in a nutshell - LINQ Quiz

Try yourself to see what your is your level and where you can get if you read\code more of this stuff (tip: C# 3.0 in  a nutshell is a great book)

Enjoy.

Monday, February 11, 2008 3:13:29 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
C#3.0 | LINQ

# Wednesday, November 28, 2007

Here at Doron's post about Object Initializers he raised a question about the IL generated from the compiler while generating Object Initializer.

            //Object Initializer
           GeoPoint point1 = new GeoPoint() { 
                             X=22.555,
                             Y=36.444,
                             CoordinateSystem=GeographicCoordinateSystem.Wgs84 };
            //Associative Init
            GeoPoint point3 = new GeoPoint();
            point3.X = 22.555;
            point3.Y = 36.444;
            point3.CoordinateSystem= GeographicCoordinateSystem.Wgs84;

That two samples are not the same, this is because of not having an atomic assignment possibility at the second piece of code.
you can have further reading at Bart's blog post.

Enjoy.

Wednesday, November 28, 2007 6:08:08 AM (GMT Standard Time, UTC+00:00)  #    Comments [2] - Trackback
.Net 3.5 | C#3.0 | LINQ

Archive
<April 2014>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2014
Shani Raba
Sign In
Statistics
Total Posts: 146
This Year: 0
This Month: 0
This Week: 0
Comments: 97
Cool Stuff
Add to Technorati Favorites
Themes
Pick a theme:
All Content © 2014, Shani Raba
DasBlog theme 'Business' created by Christoph De Baene (delarou)