Joe Moore's blog
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.
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…
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):
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.
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_photosa_user.photos.createwill create and persist both a Photo object and the UserPhoto join objectphoto = a_user.photos.buildfollowed byphoto.savewill create and persist the Photo object only, and will not persist an appropriate UserPhoto join object.
Rails 2.2:
Test::Unit::TestCaseextentions have been removed from Rails Core and are now inActiveSupport::TestCase. As stated in the Groups Thread about this, useActiveSupport::TestCaseinstead ofTest::Unit::TestCasein test/test_helper.rb.
Interesting Things
We recently updated Pivotal Tracker's extensive JSUnit test suite to be compatible with the Google Chrome browser. Check out the extensive Notes on Google Chrome Compatiblity post by Pivot Chad.
ActiveScaffold + Rails 2.2 = BOOM. ActiveScaffold will work with Rails 2.1 if you get the version from github. Read about it.
- Rails 2.2 + Rspec 1.11 = FAIL
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 :photoswhere 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:
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_methodmethod! 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

