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

# 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

# Friday, May 30, 2008

I had the honor meeting Tom Brown, here in Israel. Systematics (the representative of Esri in Israel) bring him to three days. On Wednesday Tom gave a lecture about SDE- new features and Performance and on Thursday he had a one-on-one meetings. I hope Tom will publish his presentations so I could link it from here.

Here are some tips I've learned from those two days:

Register all your tables
You might register all your tables with ArcSDE using sdetable -o register (even the non-geo-layers), this will add a row to the GDB_OBJECTCLASSES. The main reason is optimizations, for each time the ArcObject api will try to access your tables\layers he won't need to search for it all over the tables-dictionary.

Do NOT overload feature datasetes just for managing it better. You probably ask why? This is because when editing and browsing the layer it will initialize all the classes underneath the dataset. use this only for Topology and Geometric Networks.

Profiling your SDE (enabling sdeintercept)

you can enable it as a client or maybe as the server, I'll probably use it in my ArcGIS Server, so  for me I need to install the SDE client libraries, after installing you will need to set the sdeintercept variable, you can put this line in a batch file and run it whenever you need it:

   1: set SDEINTERCEPT=crwtf 
   2: set SDEINTERCEPTLOC=D:\tmp\sde_server

Intercepting the operations to SDE will create a huge file so it will be a good practice to enable it for a specific operation, watch the file to understand what happen clear it and start over again for another operation. I didn't try this yet, but I will publish more on it whenever I found more time.

Move edits to base option (Versioning-workflow)
We all know the Versioned and the non-Versioned pros and cons, ESRI give us new option, now we can work like a versioned option, but still our data will be save and accessed as non-versioned (with one DEFAULT table of data). you will be able to query the main table using simple SQL and without the need for Compress it from time to time. this model called the Move edits to base option (aka: Hybrid model)

Geodatabase and Raster's archiving
At my project we handle a huge processes of loading large Rasters to the SDE, this operation can take some time but the main problem is that your database is archiving each bit to help it recover failures. Archiving operations cause the redo-log to grow and blow, which cause us to turn off archiving. Tom also showed a command for turning off the archiving. At Thursday he thought loud of another idea, that, maybe, in the next versions the loading of Rasters will be using direct write which will bypass the redo logs.

Spatial Types
Oh boy, this is a syntactic sugar, from the 9.2 versions (oracle) you can write such bunch of code

   1: SELECT sa.name "Sensitive Areas", hs.name "Hazardous Sites" 
   2: FROM   sensitive_areas sa, 
   3:        hazardous_sites hs 
   4: WHERE  
   5:        ST_Overlaps (sa.zone, ST_Buffer (hs.location,.01)) = 1;

 

   1: INSERT INTO hazardous_sites 
   2: VALUES (1, 102, 'W. H. Kleenare Chemical Repository', db2gse.ST_PointFromText('point (52 24)',1)

 

You can extend your reading here.

Two tips for the next versions:
TDDer prespective:
Testing spatial queries is hard but important, as you can see the query above there are many scenarios:

  • point inside an area
  • point outside the area
  • point on the area border

Here I would be more than happy to have a test table to see the results, and to give a better readability for the next programmer who would like to run my query.

Keep it simple:
As you can see the insert statement I need to know the next number for insertion it is also connected to another table in the database. I don't want my programmers to bother about this index, as I see this it can be solved by adding an automatic triggers while registering the layer as Geodatabase.

Friday, May 30, 2008 2:37:18 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
DataBase | GIS | SDE | TDD

# Monday, April 21, 2008

The last day of Tech-Ed, two more lectures to go:

TDD, MVP & UX - (by Ron Jacobs)

Ron made a great lecture, about Test-Driven-Development and about having a rich User-interface (or as he called it, not only interface but also experience - with events) but still can test it using Model-View-Presenter pattern. he also explain the differences. Here are some great posts for the differences: Martin Fowler, Alex, Nikola.
He also talked about Passive View. and showed a great code sample (I didn't find the presentation or the code in his blog, The sample was great, I wish it will be uploaded to its blog)

My grade to Ron's lecture: 9/10

 

F# Introduction - (by Luke Hogan)

Luke had a great lecture about the F#. F# is a functional (and Object Oriented) programming language for .Net, which is something very geeky I might say. (you can found his lecture & samples here).
There are some cool things I found useful in this language such as using the let for variable and methods using the same syntax, for example:

let data = (1,2,3)
let g(x) = sum + x*x

the data is immutable by default so it will reduce the frequency of bugs by reducing the amount of special case-code. it is also can be passed between threads easily.
Something else in the F# is the pattern matching you can use (I didn't realy know the syntax so it would be better for you reading the code at Luke's blog).

you can train yourself with F# using this tutorial.

Why using F#? 

it still not so clear for me, but as Luke said: It is a bridge between the the Dev team and the Research Team. Luke also recommended the usage for the F# for Data-Mining because of the pattern matching, and for scientific data analyst.

My Grade to Luke's lecture: 9/10

 

This is the last post for the TechEd week (here is a link to Day 1, Day2).

Monday, April 21, 2008 11:59:12 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
.Net | .Net 3.5 | TDD

# Thursday, October 04, 2007

For the last few weeks I read a lot on how to improve my team's Scrum environment and on how to create a more Agily workspace. I might also add here that we Scrumming for 9 months (on each month we change something else, improving, destroying, thinking again, etc...).

Collecting and reading great posts, I will share them with you:

Those few Samples cause me think about how can I upgrade our environment, And I'll Explain my changes:

Programmer environment - better productivity
Upgrading the Programmer environment to a more productive workplace - Thanks to Yossi
, we have two screens for each programmer. Now everyone can code on once and test on the other screen Or maybe can code on one and read the Design Requirements on the other, etc.

Cork board 
I've found out that most a the programmers do not really understand what everyone telling at the daily-standup-meeting, which cause them to dislike the meeting or maybe even forget the importance of this meeting.
The Cork-Board will help us to see (visualization) and understand(movement-at-realtime) the actual point of the team in the current sprint.

Done
People are different, This is a good fact, and we should understand it.
You need every one in your team understand what the Team want from him only his best. But when we can't explain ourself, someone can understand things not properly as we meant them, this will cause anger and disappointment.
Create a short document explaining what is Done - so everyone will be coordinated.
(Some types for Tasks that need to be Done: Writing Story Cards, Updating documentation, Coding, Bug-fixing. each one of those need to be fully Done)

Testing (not TDD yet)
Logic:
For me, one step before TDD-ing, the team must have a solid tests and a good understanding about the difference between integration, functionality and unit.
Framework:
After understanding the logic, you must have a solid framework for testing and a daily notification about your operations, so you and everyone else could see that you are working as we expect you to work.
So we create the Continuous-Integration workspace using the CC-Tray so everyone could know whether their friends are helping them or preventing from them to work properly.

The Imporatnce of testing:
After having this simple understanding, and this framework, everyone will finally understand that his testing methods are important.
And everyone will understand that unit-testing are part of the Done statement.
Moving to TDD-ing:
From here I believe that we could move toward TDD-ing.

Daily Scrum Standards
Right on time meeting, Every one standing, Only one people talking, Exactly 15 minutes, clarifications questions only.
Selecting the leading watch - everyone has its own watch, the team should understand which-watch is the one to set the scrum time. (I should buy an Egg-Watch, I am still looking for a funny one).

Setting Punishments (Penalties)
They should be a funny penalties, so everyone will like it (everyone but the one who doing it, of course).
like bringing the milk, or making coffee for everyone.
I see those punishments for a few fields:
a) destroying the build(errors and warnings)
b) checking-in tests that fail
c) decreasing the Code-Coverage,
d) late for Daily-Scrum


Here are some pictures from the new environment


                                            My Agile Workspace 


                                           Two Scrum Boards

 
                           The new Cork-Board (still empty, till the next sprint)



Things To Be Done, {Till the end of the year}:

  1. Find a funny (noisy) Egg-Watch
  2. Create a field_penalty_list
  3. Moving toward a TDD-ing sessions
  4. Decide about the best period for the sprint (today we decide about two weeks, I am start thinking this one is too short)
  5. Find the Product-Owner (This one may sounds funny, but we still did not find him\her, no one can take this position for now)

Scrum is not only the things you are saying and doing, it is more about what you (and your team) are feeling.
Scrum should be part of everyone in the team, so it will succeed.

 

Thursday, October 04, 2007 2:41:11 PM (GMT Daylight Time, UTC+01:00)  #    Comments [2] - Trackback
Agile | Scrum | TDD

# Sunday, February 18, 2007

Hi, so this is my first step in the TDD world, First read "TDD: from beginner to pro" introduction.

I Had to write a decision tree algorithm which has a special format (SVMLight format). The algorithm should run on this data and create the tree. I will focus on the SVMLightVector class.

I should also add that my examples for this session would be taken from the world of text mining.
our samples would be documents and we should classify each document to its subject.
for example if we hold a document D1 (bunch of words separated by spaces), the decision tree would help us to decide whether this document (D1) is a sport article or finance.

the SVMLightVector class holds:

  • Features - for example if we hold a document each word is a feature.
  • Classification - the subject of the features.

so I wrote this code, or if I'll be TDD-ly Correct: attend to write this code:

public class SVMLightVector
{
   private IList<string> m_classifications;
   public IList<string> Classifications
   {
      get { return m_classifications; }
      set { m_classifications = value; }
   }

   private IDictionary<string, long> m_features;
   public IDictionary<string, long> Features
   {
      get { return m_features; }
      set { m_features = value; }
   }

   public SVMLightVector()
   {
      // do nothing.
   }

   public SVMLightVector(string svmLightFormat)
   {
      Classifications = new List<string>();
      Features = new Dictionary<string, long>();
   }
}

So I thought to myself... Testing properties? isn't it wasteful? so I decided to stop wasting my time and start coding.
So why do I think it is good to right such tests:

  • because that this is what I read in all TDD books, test everything, do not have even one line not tested...
  • why not?! it is simpleasy (simple&easy)....
  • also, I must admit that I found it useful to write those tests for properties, how many times it happens that you copy&paste&change one property to another one, instead of using the snippet, this trick can cause strange bugs, believe me.

so here are my tests:

[TestMethod()]
public void FeaturesProperty_SetProperty_GetTheSame()
{
   IList<string> classifications = new List<string>();
   classifications.Add("class1");

   IList<string> expectedClassifications = new List<string>();
   expectedClassifications.Add("class1");

   SVMLightVector vector = new SVMLightVector();
   vector.Classifications = classifications;

   //Assert.AreEqual<IList<string>>(expectedClassifications, vector.Classifications);
   CollectionAssert.AreEqual((IList)expectedClassifications, (IList)vector.Classifications);
}

[TestMethod()]
public void FeaturesProperty_SetPropertyToWrongClass_GetDifferentClass()
{
   IList<string> classifications = new List<string>();
   classifications.Add("class1");

   IList<string> expectedClassifications = new List<string>();
   expectedClassifications.Add("class2");

   SVMLightVector vector = new SVMLightVector();
   vector.Classifications = classifications;

   //Assert.AreNotEqual<IList<string>>(expectedClassifications, vector.Classifications);
   CollectionAssert.AreNotEqual((IList)expectedClassifications, (IList)vector.Classifications);
}

Simple isn't it?
You can see my first Test-Bug. I tried to use the Assert.AreEqual<> which is not what I needed, because this one compares objects.
but I easily found this: CollectionAssert.

One Question to myself:

  • Why it(CollectionAssert) doen't use generics?!


Good night for now.


I should thanks to two people that don't even know that I've learned from them a lot.
1) Roy Osherove - I've been reading his blog and using his standards of naming test methods and some more standards.
2) Oren Ellenbogen - Which I read his code and start learning this stuff from their.
Sunday, February 18, 2007 1:06:37 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.Net 2.0 | TDD

# Saturday, February 17, 2007

Hi, This week I will give you a closer look to my daily coding project.

My project is an exercise in machine learning lecture.
The project itself not really matter, I would like to use it to learn some new stuff and have a lot of fun.

I must admit that I have some challenges in the next few days:

  1. Time is running out and I am not one of those that have spare time to code at home.
  2. ML - I don't understand this stuff.
  3. TDD - I code some samples but not a real project.

I hope it will be useful for some other readers.

Saturday, February 17, 2007 10:35:54 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.Net 2.0 | TDD

Archive
<October 2014>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
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)