Monday, April 02, 2012

Android Unit Testing - A slightly painful experience

After a few months of mucking around with Android it came to build something substantial. Things have been going fairly well until I started trying to add Unit Tests.

Android provides a complete framework for unit testing which builds on JUnit 3. All in all, this seems pretty good and things are fairly straight forward. The thing that caused the pain and frustration was in resource management.

First of all, let's summarise the test I was trying to implement:

  • My app executes REST requests against a web service. This returns JSON that is then parsed by a Proxy class into my model classes.
  • The REST queries themselves are executed by the Proxy via a RestUtil class.
  • To facilitate testing of the parsing code, the RestUtil class is defined by the interface IRestUtil. The Proxy constructor accepts an IRestUtil object.
  • This allows me to create a MockRestUtil that implements IRestUtil. This can be passed to the Proxy in my unit tests to allow testing of specific responses.


So with that in place I came to implement MockRestUtil. The aim was to get the MockRestUtil to load saved chunks of JSON stored locally as assets. This way I can test a whole variety of responses from the web service easily.

Once it came time to load the resources though, I never got anything back but null. I had been trying to use ClassLoader.getResourceAsStream(), however this returned nothing but null. I also tried making a static application context and using getContext.getAssets(), again nothing but null. I tried a lot of things, however, it wasn't until I hit upon the following Stack Overflow article that I finally got things working: http://stackoverflow.com/questions/9898634/how-to-provide-data-files-for-android-unit-tests

To summarise (based on Eclipse):

1) Right Click on your Test Project and select Build Path -> Configure Build Path
2) Under the Source tab click "Add Folder" and select the Assets directory. Note: Since Version 15 of the ADT plugin, the Assets folder is NOT include in the build path by default. You have to add it manually.
3) Create your data files and add them into the /Assets directory of your test project.
4) To access them in the test case use the following:

String assetPath = "assets/data.json";
InputStream stream = this.getClass().getClassLoader().getResourceAsStream(assetPath);

And there you go. Now you have an easy way to store local data for use in Unit Tests.

Friday, February 03, 2012

Implement a Week Iterator in C# using DateTime, IEnumerable and Extension Methods

I had a problem to solve. It wasn't a difficult problem, it was just one of those yucky problems I've done numerous times before and for some reason just always feels hacky.

The problem was this: For a given date range I wanted a list containing the date of the start of each week within that range. To be clear: The first date did not need to be within the range. Rather, the first date would normally be the Sunday of the week in which the first date fell.

This isn't an unusual thing to do and it is something that is done often in reporting tools.

This is also the perfect case study for writing an Extension method on DateTime that returns an IEnumerable. Doing this results in an easy, elegant and reusable solution that is no longer a hacky function buried in a class somewhere, but an extension to an already ubiquitous class (DateTime).

First up, this is implemented uses an Extension Method on the DateTime class. In C# extension methods allow you to add methods to an existing class without having to derive from the class or change and recompile the class. A couple of things about Extension Methods:
  • They are always static (that includes class in which they are defined and the method itself)
  • The first parameter is always the class which the method operates on proceeded by this.
  • Extensions are only in scope when you import the namespace in which the method is defined with a using statement. 

So, the prototype for my new extension method will look something like this (I'm calling the method EachWeek):

namespace Extensions
{
  public static class MyExtensions
  {
    public static IEnumerable EachWeek(this DateTime start, 
    DateTime end)
    {
       ...
    }
  }
}

In our calling code, this means I can now use this function as follows:

using Extensions

...
DateTime endDate = DateTime.Now.AddMonths(2);
IEnumerable weeks = DateTime.Now.EachWeek(endDate);

Iterating over weeks will now return each of the Sundays from the first Sunday before DateTime.Now to the last Sunday before endDate.

Using the above template, it's now simple to extend this to implement EachDay, EachMonth and EachYear.


The implementation of the function itself is as follows:

public static IEnumerable EachWeek(this DateTime start, DateTime end)
{
  // Remove time info from start date (we only care about day).
  DateTime currentDay = new DateTime(start.Year, start.Month,

  start.Day);
           
  // Get the dayOffset and subtract this from the current day,
  // this will give us the start of the first week.
  int dayOffset = (int)start.DayOfWeek;
  DateTime currentWeek = currentDay.Subtract(new TimeSpan(

  dayOffset, 0, 0, 0));
  while (currentWeek < end)
  {
    yield return currentWeek;
    currentWeek = currentWeek.AddDays(7);
  }
}

For more information on Extension methods see:
http://msdn.microsoft.com/en-us/library/bb383977.aspx
http://msdn.microsoft.com/en-us/library/bb311042.aspx

For more information on IEnumerable and Yield return see:
http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
http://www.dotnetperls.com/yield