Joe Moore's blog



Joe MooreJoe Moore
Android Tidbits 6/8/2011: Warning! Warning!
edit Posted by Joe Moore on Thursday June 09, 2011 at 10:00AM

Un-shadowed Method Warnings!

In response to yesterday's question about Un-shadowed Method Warnings, Pivot Tyler points out that you can turn these on by calling Robolectric.logMissingInvokedShadowMethods(). Thanks!

Bad cached-robolectric-classes.jar

On two workstations every unit test was failing with the following error:

// …many levels of stack trace, finally:
Caused by: com.xtremelabs.robolectric.bytecode.IgnorableClassNotFoundException: msg because of javassist.NotFoundException: android.content.DialogInterface$OnShowListener
at com.xtremelabs.robolectric.bytecode.AndroidTranslator.onLoad(AndroidTranslator.java:80)
at javassist.Loader.findClass(Loader.java:340)

Cause: there was an old tmp/cached-robolectric-classes.jar that was causing these errors and our tests ran successfully after deleting it. That's two answers from Pivot Tyler!

Don't DDOS Yourself With Your Own App

The Bump Android team wrote an article about a good idea gone wrong. Moral of the story: not all devices behave the same, and this might cripple your servers rather than the devices.

Robolectric Google Group

Join it, contribute, and learn about unit testing your Android apps.

Joe MooreJoe Moore
Pivotal Android Tidbits 06/07/2011
edit Posted by Joe Moore on Wednesday June 08, 2011 at 06:53AM

We're trying an experiment: since we currently have several Android projects at Pivotal Labs, and Android development and testing is hard, we are going to post to the blog the tips, tricks, gotchas, and conundrums we find.

Emulator and Orientation

Android will destroy and recreate activities upon screen orientation change. One way to prevent this is to set android:configChanges="orientation" in your AndroidManifest.xml (article here):

<activity android:name=".activities.MyActivity"
          android:configChanges="orientation"/>

This prevents android from calling onPause() => onDestroy() => onCreate() on a device, but not within the emulator; annoyingly, the Activity is still recreated within the emulator.

Un-shadowed Method Warnings?

Once again we spent about 15 minutes debugging a failing unit test only to find that there was no Robolectric implementation/shadow for one of the Android methods under test (ArrayAdapter#insert in our case). I would be nice to have a "warning mode" where Robolectric would log warning for all un-shadowed methods. I wish we knew the guys who wrote Robolectric…

Joe MooreJoe Moore
Testing Desert Plugins in Isolation
edit Posted by Joe Moore on Saturday August 22, 2009 at 11:37AM

At Pivotal, some of our client projects use plugins from our home-grown social networking platform and rely on Desert to tie them all together. To test this package of plugins we created a project that contains all of our Desert plugins and wrote some rake tasks that run all of their tests. Great, right?

Mostly. We want to ensure that our plugins have the absolute minimum dependencies to function. Let's pretend we have an UserAuth plugin and a SocialPivots plugin, where UserAuth has no dependencies, but SocialPivots depends on UserAuth. We would like to test these the to plugins in isolation. But, with Desert doing it's job so well, our UserAuth plugin could have a dependency on the SocialPivots plugins' models or tables and we would never know it. Everything from SocialPivots is mixed-in and loaded into memory, and all of its migrations have executed, at the time we are running UserAuth's tests.

What we need is a way to tell Desert to load only the plugin under test, plus its dependencies listed in init.rb. Hacking Desert and Rails to allow us to specify which plugins to load turned out to be pretty easy. Check it out (full gist here):

Joe MooreJoe Moore
DRY, Targeted, and Reusable Testing of ActiveRecord Extensions
edit Posted by Joe Moore on Wednesday March 18, 2009 at 08:39PM

At Pivotal, we are passionate about test driven development, keeping things DRY, and writing readable and understandable code. Satisfying all of these desires can be challenging, especially when writing test code. In particular, ActiveRecord extensions present several challenges: which models using an extension should we test? How do we both test our extension in isolation while also testing all model's usage of that extension? Is it even worth it?

The answer is yes, it is worth it, and it's also fairly easy, readable, understandable, and DRY. I will present both a common problem and a solution, using a cumulation of technologies and techniques from multiple Pivotal projects, in particular using acts_as_fu to create laser-targeted, isolated, and disposable ActiveRecord models for testing extensions and RSpec shared behaviors to minimize the amount of duplicated test code.

Joe MooreJoe Moore
Standup 11/18/2008: Unbelievable has_many :through Gotcha
edit Posted by Joe Moore on Tuesday November 18, 2008 at 11:53PM
  • One team discovered a jaw-dropping issue with has_many :through. Given the following:

    class User < ActiveRecord::Base
      has_many :user_photos
      has_many :photos, :through => :user_photos
    
    • a_user.photos.create will create and persist both a Photo object and the UserPhoto join object
    • photo = a_user.photos.build followed by photo.save will create and persist the Photo object only, and will not persist an appropriate UserPhoto join object.
  • Rails 2.2: Test::Unit::TestCase extentions have been removed from Rails Core and are now in ActiveSupport::TestCase. As stated in the Groups Thread about this, use ActiveSupport::TestCase instead of Test::Unit::TestCase in test/test_helper.rb.

Joe MooreJoe Moore
Standup 11/17/2008: Google Chrome Gotchas
edit Posted by Joe Moore on Monday November 17, 2008 at 11:31PM

Interesting Things

Joe MooreJoe Moore
Standup 11/07/2008: Selenium for Flash
edit Posted by Joe Moore on Friday November 07, 2008 at 05:23PM

Interesting Things

  • Teaser: Selenium for Flash! We've developed a Selenium-like framework for Flash. It's pre-alpha, and needs to be extracted from it's current home inside a project. Are you interested in a Selenium-like framework for Flash, or have you written one yourself? Let us know!
  • STI-weirdness. Rails surprise of the day: given a query of a has_many :photos where Photos has STI subclasses (got that?) Rails will build a SQL query that includes the subclass types of Photo, which you might not want:

    foo.photos.find_by_type("Photo") 
    # query will have "... WHERE type IN ('Photo', 'OriginalPhoto', 'ThumbnailPhoto')"
    
  • It appears that the retardase_inhibitor might not work with Rails 2.1.X due to fixes in ActionMailer.

  • JetBrains has been hard at work: they have released both a new Ruby plugin for IntelliJ, and a ruby-specific IDE (based on IntelliJ) named RubyMine.
  • Check out Pivot Jonathan's wife's art exhibit at Artist-Xchange Gallery in San Francisco, Friday 11/7 from 7-10pm:

    Artist-Xchange Gallery
    3169 16th Street
    San Francisco
    CA 94103

Ask for Help

"I want to create a custom launcher for Firefox 2 and Firefox 3 with different profiles. Perhaps the real question is how do we create a custom version of a Mac application launcher, passing in the arguments we need?"

... without having to invoke it on the command line every time.

"We're trying to delete cookies in our Controller, but they keep appearing in the headers anyway."

Suggestion: make sure you are specifying your URL paths and domains correctly.

"Why won't our CSS and other assets load the first time when accessing an SSL-protected domain on Engine Yard?"

It's most likely not Engine Yard or Firefox 3's fault. More research needed.

  • Where am I? -- Ever need to find the name of the method you are currently within? Here's a this_method method! The magic is in the REGEX, of course.
module Kernel
  private
  def this_method
    caller[0] =~ /`([^']*)'/ and $1
  end
end
  • One project wanted to test a very ActiveRecord-specific Module in an isolated, generic way. After spending time researching techniques of mocking and stubbing the many, many ActiveRecord methods that would be touched, they decided to just dynamically create an ActiveRecord and a DB Table for it on the fly! They even used single table inheritance (STI)
  describe "MyMagicModule Mixin" do
    before(:all) do
      ActiveRecord::Base.connection.create_table "some_base_models",
                                                   :force => true do |t|
        t.string   "name"
        t.string   "type"
        t.integer  "some_model_b_id", :limit => 11
      end
    end

    after(:all) do
      ActiveRecord::Base.connection.drop_table "some_base_models"
    end


    class SomeBaseModel < ActiveRecord::Base;end

    class SomeModelA < SomeBaseModel
      include MyMagicModule

      belongs_to: :some_model_b
    end

    class SomeModelB < SomeBaseModel
      include MyMagicModule
    end

    it 'should use special belongs_to stuff from MyMagicModule' do
       model_a = SomeModelA.create!(
                        :name=> "Model A",
                        :some_model_be => SomeModelB.create!(:name => "Model B"))
       # test the functionality from MyMagicModule
    end
  end