Creating Test Data for Rails Apps

I wrote a guest post over at 3 Weeks to Live on our progress in building data sets for testing OnCompare under Ruby on Rails.

The biggest challenge has been generating a large number of records, but I think we can do that with loops and factory_girl:

The other place to use large data is to stress test the system. … I need to know that the algorithm will continue to be responsive when we have 300 products. At this point, I’m looking at running loops around factory_girl calls so that it will generate most of the non-essential information. [Settings] up a single product matrix may take a dozen records, but I can loop over that 300 times and factory_girl will automatically create records with new names (using the sequence method shown in the factory definitions above).

before do
  category = Factory.create(:category)
  300.times do
    product = Factory.create(:product, :category => category)
    12.times do
      Factory.create(:question, :category => category, :product => product)
    end
  end
end

As a follow-up, we also added Faker to our gem set, which has a ton of handy methods for mocking up data. So, for example, I can set up a factory definition with Faker::Lorem.words(3) for the name or description of a product and 300 products will all look different. It’s pretty sweet.

OnCompare: Can we build a company in three weeks?

So, I’m in the middle of an interesting experiment. A group of guys I know invited me to join them for a 3-week run to try to build a technology company. That means software, market and customer base in three weeks. The product we’re working on, OnCompare, will allow you to rank and find on-line services, based on the most critical criteria for the class of service. For example, looking at email services you could decide whether templates are important or whether you need survey support. Because we’re doing this in three-weeks, we also decided to blog the whole thing so that the process is (mostly) transparent.

My role, along with entrepreneurial advisor, is straight dev work right now. But I am evaluating this as a technology tool, because I see this kind of rapid prototype practice happen in events but rarely within companies. After attending some 8-hour Startup events several years ago I wanted to try stopping our consulting company for a day to run the whole company on a single project. From a consulting perpective this could be a huge differentiator: while large projects take a while, slipping them a day is no big deal; but if a potential client can be sold with, “we’ll get something up and running by the end of the week” that could be the closer. We never got to do it while I was there because (a) we never had a potential client that needed that and (b) we didn’t have unanimous support, which I felt we had to have.

Do you think this whole-team/company sprint idea (e.g. 8-hour Startup, Startup Weekend, Hackathons, etc.) can be integrated into your company (Facebook tried it)? Clearly there’s desire for it among developers. Can that be supported and used to develop new ideas, to break the monotony of the daily drudgery?

My colleague Ruben Ortega wrote Why do Software Developers Tolerate “Crunch Time”? last summer for the Communications of the ACM, which sparked a deep conversation about this topic. Sometimes we want the herculean effort to feel like we’ve accomplished something. But does a full-team sprint like this produce something you can put into production?

Most of these events are focused technical accomplishments (engineering, some testing, graphics). I recognize that customer development is a long-running process but clearly you either have an idea to start testing or a market demand to try to fit when you start this event. Do you think that marketing and (some) customer development can happen in a short time too? While three-weeks is much longer than a weekend or a hackathon, we’re testing whether it is long enough to build a customer base.

Opscode Chef makes operations fun

Years ago, I did some time helping companies plan and build networks and computer infrastructure. Since then, in several companies, I’ve done my share of operations and IT work, but more recently I’ve found that I prefer to delegate that work to someone who finds it more interesting. I’ll be honest; I find the ever-changing complexity of systems configuration to be a frustrating, never-ending learning problem. (This particularly applies to mail server management.)

Over the past month I’ve been playing with Chef and the Opscode Platform and found that I absolutely love learning a new framework that gives me new development tools for solving an existing problem. This means that my argument, above, is entirely irrational. Let me put that another way: Chef is damn cool. Continue reading “Opscode Chef makes operations fun”

Subversion Revision in Android App Version with Eclipse

As developers, we like to know exactly what code our customers are running when they report a bug. For years, across several companies and many projects, we’ve put the source control revision number into the reported version number. This works well and is a common practice. Here’s how we’re doing it for Android apps.

Continue reading “Subversion Revision in Android App Version with Eclipse”

Location (GPS) and Automated Testing on Android

So I’ve been contributing to the NPR Android App, specifically by building a test suite and tests for outstanding bugs. While my specific interest is in the audio playback, I took on some sticky issues around the location lookup and found that testing location services isn’t as straightforward as I thought. So here’s a quick primer with some notes to get you started.

Getting the device’s location

Android devices can get location from the (cellular) network or the GPS chip (if they have them). Some devices may support other providers in the future. The emulator only has a GPS provider (emulated of course) registered on start-up.

The quickest way to get the location of the device is to call LocationManager#getLastKnownLocation.

LocationManager lm =(LocationManager) getSystemService(Context.LOCATION_SERVICE);
Location location = null;

List providers = lm.getAllProviders();
for (String provider : providers) {
  Location loc = lm.getLastKnownLocation(provider);
  if (loc != null) {
    location = loc;
    break;
  }
}

Note this call is synchronous but in order to not block the thread during a lookup, it just looks for a saved location from the given provider. Therefore, it does not actually do a network or GPS location lookup.

For rapid response, this is what you want, and most of the time that will work well in your apps. Some other application (like Google Maps) has probably already found the location recently. However, when testing the application, it’s very likely the emulator will not have a location and this call will return null (which, according to the SDK docs, means there is no provider but it can also mean the provider hasn’t located the device yet).

To locate the device, you’ll have to set up a listener. There’s a small likelihood that your app is the first (location-based) app your customer started after turning on the phone. In that case it would be the same problem — no location. So what you probably want to do is have your initial activity launch a listener on one or more providers to record a location. This is asynchronous so it doesn’t block your app. Here’s an example of how to do that.

  private static final int MSG_CANCEL_LOCATION_LISTENERS = 2;
  private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case MSG_CANCEL_LOCATION_LISTENERS:
        cancelLocationListeners();
        break;
      }
    }
  };

  // This is public so that we can inspect if for testing
  public List locationListeners =  new ArrayList();

 /**
   * On start up, launch a location listener for each service. We need to do
   * this in order to ensure that getLastKnownLocation
   * will always find a value.
   */
  private void lauchLocationListeners() {
    LocationManager lm =
        (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    List providers = lm.getAllProviders();
    for (String provider : providers) {
      LocationListener listener = new LocationListener() {

        @Override
        public void onLocationChanged(Location location) {
          handler.sendEmptyMessage(MSG_CANCEL_LOCATION_LISTENERS);
        }

        @Override
        public void onProviderDisabled(String provider) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

      };
      lm.requestLocationUpdates(provider, 60000, 0, listener);
      locationListeners.add(listener);
    }
  }

  /**
   * Remove all listeners.
   */
  private void cancelLocationListeners() {
    LocationManager lm =
        (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    // Synchronized because there may be multiple listeners running and
    // we don't want them to both try to alter the listeners collection
    // at the same time.
    synchronized (locationListeners) {
      for (LocationListener listener : locationListeners) {
        lm.removeUpdates(listener);
        locationListeners.remove(listener);
      }
    }
  }

Testing the location

The SDK provides methods for mocking location providers and location details for your testing. (You can also change the geo fix with DDMS in Eclipse or through the console, but I’m interested in automated testing here.) It wasn’t very clear from the documentation on how to use them so it took me a while to figure out that all the ‘test’ calls are not necessarily related.

addTestProvider

This method places a new provider (with the name you gave it) in the collection of providers returned by getAllProviders() (and other calls). You cannot add a mock provider with the same name as a provider that already exists, such as “gps”. This will cause an error. The mock provider doesn’t allow you to pass in a class, so it’s not very useful for inspecting actions called on it (which is why I usually use mocks). Instead it just lets you create a provider that will return in response to specific criteria.

The corresponding removeTestProvider removes this entry from the list. You should remove the provider as you clean up your test because otherwise your next test won’t be able to create it again. (The provider is retained in the emulator instance, even if the activity is destroyed and recreated between tests.) Note that you can actually remove any provider, even the built in “gps” one with this call, so be careful. If you do that you’ll have to restart your emulator to get the emulated GPS interface back.

setTestProviderLocation

I think this method should have been called “setTestLocation” because it is not directly related to a “test provider” made in the previous call. You can set a test location, with this call, for any provider. In fact, if all you want to do is test that your application can find a particular location, then set a location on the GPS provider and ignore the ‘addTestProvider’ method completely.

      LocationManager lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
      Location location = new Location(providerName);
      location.setLatitude(latitude);
      location.setLongitude(longitude);
      location.setTime(System.currentTimeMillis());
      lm.setTestProviderLocation(providerName, location);

Be sure to set the time on your location if you want the provider to think it’s a new update.

Also, all the testing requires that you have permission for mock location requested in your application under test (not in the test project). Add this to your manifest.

<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

If you are testing on a device, you’ll need to go into Settings | Applications | Developement | Allow Mock Locations and enable it, which is not set by default. This setting may not exist on all devices (but there’s a workaround).

setTestProviderEnabled

By now you should be getting the picture. This method doesn’t enable your test provider, it sets a value that indicates to your application that a provider is enabled whether it actually is or not.

Hopefully this will help some other folks who were confused about the terms in the SDK.

Testing Challenges

As mentioned above the SDK is not very conducive to dependency injection. What I’d like to do is inject a real mock provider object (one I create in my test) into the provider list for the app and when the app asks the GPS provider for a location I know the app is working. This isn’t possible as it’s currently built so I have to write silly tests with threads to start the activity and check when it collects and removes its listeners. Not very clean (and really testing the wrong thing). In many places in the SDK, I’d like to be able to inject mock objects into the system, but this isn’t thoroughly supported yet.

The second challenge is that you can’t access the location manager without access to the activity because it’s returned by the context of the activity. This makes it impossible to, say, inject a mock provider or location before the activity starts, which you might like to do in the case of, oh, looking up location in the onCreate call.

If anyone has any suggestions on this, I’d be excited to hear them. Perhaps I’m just missing a basic concept here.

Mail integration testing without spamming the world

I was recently reviewing this scenario with a client. In my last company we used to run a lot of scheduled email systems for notifications. That was great in practice but in testing we had to make sure we didn’t send test emails to live account. We really wanted to test the email system (and we hadn’t yet isolated the email for unit testing), so we needed to catch emails and stop them from being forwarded.

After a little searching I set up Jeff Brown’s Loopback Mail Server. In retrospect, this is one of my most favorite test tools. It’s simple. It works. It requires you buy a library, but that’s pretty cheap.

Android Audio Streaming

Having spent hours and hours trying to figure out how to get MediaPlayer to work properly on a thread for my last video project and now an audio streaming app, I found there’s an easier way.

The AsyncPlayer class takes care of this for you.

player = new AsyncPlayer(TAG);
player.play(this, Uri.parse(stream), false, AudioManager.STREAM_MUSIC);

For some reason the PocketJourney streaming tutorial for Android 1.0 keeps ranking in all my searches, which is generally too bad because that’s way out of date (incidentally, here is the newer version for 1.5 and later). You don’t need to buffer or double buffer media for the media player anymore. However, the comments on there helped me find AsyncPlayer as well and the 3GP file that Anthony posted to test this.

Now, the next step is to figure out how to get MediaPlayer (which underlays AsyncPlayer) to play an MP3 stream. I don’t know why it won’t, as MP3 is a supported type, but it plays nothing for my test stream.

Update Removed the link to the old streaming article in the hopes that the new one will rank better.

Update Android SDK doesn’t support streaming MP3 (shoutcast) until 2.2 (FroYo). To stream an MP3 stream on earlier OS versions you need to double buffer it either using the PocketJourney code above (which is not very good — it stutters) or using a built-in proxy as the NPR News app does.

Loading Images Over HTTP on a Separate Thread on Android

My previous post about making a list view with lazy-loaded images on Android just had the code pertaining to the list view. As requested, I’m also adding the class that loads the images.

This class includes a queue so that only a single image is loaded at a time. I chose this because in building a list view with images it’s more important to start loading some images than to wait for all images to get loaded. Other implementations of this kind of thing launch a separate thread per image which means that the network connection would be clogged with all the image loads.

You’ll notice the use of SoftReference here, which I gleaned from Tom van Zummeren’s tutorial. While this appears to work well, I haven’t done any significant load or performance testing, so it may not be necessary.

There are some notable problems here in the design, so please adapt this to your need. Beyond the potential race condition noted below, there’s a basic problem in that the thread completes once the queue is done. So if the images happened to load faster than you add them to the queue you could end up with a queue that was emptied, the thread died and future items were never loaded. I’ve tried to work around this by capturing the TERMINATED state of the thread and relaunching it, but have not, as far as I know, tested this in production. And I’ve built no automated tests to test that case yet.

Continue reading “Loading Images Over HTTP on a Separate Thread on Android”

Loading Remote Images in a ListView on Android

So this appears to be a common challenge:

I have a list of items in my mobile application. Each item in the list contains an image and a title. The data for the list comes from a remote web service, RESTful interface or other Internet connection and the images are provided in a separate call. I want the list to be responsive, so I’ll load the list and then in a separate thread I will update the images in the list as they are loaded from the network.

I struggled with this on the BlackBerry where there was little similar code to go on, but got it working. I just finished an Android app and discovered that we had the same pattern. Trying to re-use my BlackBerry code I found that the UI patterns don’t translate (beyond frameworks, Android recycles views while it’s rendering to keep memory-use low).

There are lots of posts on the web about how to do this for the Android, such as this thread.

Unfortunately all of those ran into the same problem: Sometimes the images would load and sometimes they wouldn’t. Sometimes the images in the list would be the wrong one for the list item when rendered. And some solutions only rendered images that were off screen.

Continue reading “Loading Remote Images in a ListView on Android”

Windows 7 Netbooks: Second Look

Following on my previous post about new netbooks running Windows 7, I wanted to give some of my thoughts to the platform. I spent a week working with each of the two netbooks I ordered: the Toshiba Mini NB205 and the Asus Eee PC T91MT.

Asus Eee Multi-touch Tablet

The Asus Eee PC T91MT is a tablet format netbook with multi-touch support on the screen (as well as the trackpad). It shipped with a 1.33Ghz processor, 1GB RAM and Windows 7 Home Premium. As mentioned before, this start up was really slow. It didn’t get any better. I don’t know if it’s Windows Home Premium or the 1.33Gmhz processor, but it really wasn’t fast enough to use. Everything needed to wait for a response. I get frustrated with my G1 phone doing this, but I put up with it. No way would I put up with this on my netbook. I suspect that the tablet and multi-touch drivers also slow this down a bit. Bottom line is that I know I bought a reference machine for cutting edge ideas, but until they can get this faster and under $400 it’s probably not going to see much traffic. Still, would love to see more multi-touch tablets in the market.

Toshiba Mini

The Toshiba Mini performed much better. It shipped with a 1.6GHz processor and Windows Starter. The Windows Starter version pisses me off. I mentioned it before, but it seems ridiculous to think I would pay a $90 premium on a $300 netbook to upgrade the OS that shipped with it. Here’s what really grinds my gears: you can’t change the default background of the desktop in Starter edition. You have to pay to upgrade for that privilege. The gall! No wonder small device manufacturers are looking to Android and other low-cost OSes.

Other than that, the Mini was usable and extremely portable. Like I have heard in all the marketing, it’s really easy to pick up the netbook and go. If one of them really did have a 10.5 hour battery life, well, it would be awesome. Although the keyboard was small, and I made lots of typing errors. Still with the errors, the typing was faster than an iPhone or G1.