A little while ago I wrote about Cedar, a BDD-style testing framework for Objective-C. The responses I received nearly all went something along these lines: “That’s great! Too bad I can’t use it, since I’m writing an iPhone app.”
I actually wrote Cedar specifically for testing iPhone OS projects we’re working on at Pivotal. To prove it, I’ve started a small public iPhone project that I’ve test-driven entirely with Cedar. You can get the project here (more on that in a bit); it should eventually allow you to log into Pivotal Tracker, see all the delivered stories in a given project, and accept or reject each one. At the moment it does little more than start up and display the Pivotal Chicken*, but it does contain Cedar specs that run on and off the device.
“How is this possible?” you ask. I’ve done two things to make this work:
I separated out all classes that don’t depend on UIKit into a target that builds a static library. The specs for this target run as a console app using the OS X runtime, so no need to worry about runtime support for blocks (assuming you’re running 10.6). Also no need to incur the overhead of starting the emulator every time you run tests. This is a pattern I started using ages ago to make automated testing easier on Win32 client applications, and it works great for all the mobile platforms I’ve worked on. Framework independence means faster tests, and faster tests mean happier programmers. I recommend doing this whether you’re interested in testing with Cedar or not.
Tests for the actual app, which does depend on UIKit and therefore must target the iPhone runtime, run on the emulator (or, in theory, a device) using the PLBlocks iPhone runtime for block support.
Getting the specs up and running takes a few steps, but as we all know good things come to those who wait.
Clone, or otherwise obtain the StoryAccepter project. It will probably have a number of missing library references.
You’ll need to build Cedar, both the dynamic framework (Cedar.framework) and the static iPhone library (libCedar-iPhone.a), as well as the OCHamcrest and OCMock frameworks. Fix the references in the StoryAccepter project to point to these libraries on your system.
If you’re running Leopard you’ll need to install PLBlocks 1.0 for Leopard, and you’ll need to include the runtime and set the compiler for both spec targets; the PLBlocks page has excellent instructions. If you’re running Snow Leopard the project should already contain the runtime, so you’ll just need to download and install the compiler for PLBlocks 1.0.1.
Select the DomainSpec target, and make sure you’ve selected the appropriate Mac OS X runtime for your system. Build and run; you should see dots appear in the console window as the specs run.
Select the StoryAccepterSpec target, and make sure you’ve selected an iPhone runtime (if you want to try running on a device you’ll have to set up the provisioning, of course). Build and run; the emulator should start up and try to run the app, which will simply run the specs and then exit. You should see dots in the console window, as before.
All of this still has some rough spots, especially the UIKit-dependent specs, but even so I’ve found test driving with hierarchical describe blocks far more pleasant than using OCUnit. Some things I hope to improve on:
I imagine the app that runs the UIKit-dependent specs showing a graphical display of test results, perhaps similar to what GHUnit displays when run on the emulator or device.
The iPhone doesn’t allow dynamic libraries, and I haven’t found a way to use OCHamcrest or OCMock for UIKit-dependent specs. The folks at Carbon Five describe using these libraries in their tests on the device; I’m curious to know how they pull that off.
Once iPhone SDK 4.0 comes out with support for blocks this should all work without the need for the PLBlocks runtime. That won’t help iPad development for the foreseeable future, though.
Full-stack integration testing à la Selenium.
Lots of other things. What would you like to see added to Cedar?
*Not an officially endorsed Pivotal mascot (yet).
At Pivotal Labs, one of the services we provide is helping clients interview and hire. Pivotal Labs and our clients place a strong emphasis on Agile development and its many aspects: test-driven development, rapid iterations, frequent refactoring, etc.
Here is a job posting from ProFounder, a Pivotal client looking for a senior Rails developer.
Sr. Rails Developer – San Francisco
ProFounder is a new way of crowdfunding startups and small businesses through friends, family, and social network/community involvement online. There is a huge gap and need for funding for startups/small businesses right now and ProFounder has an innovative solution for it.
Founded by Jessica Jackley (Previously Co-Founder of Kiva, the world’s first peer2peer microfinance site) and Dana Mauriello (previously an entrepreneur with real experience). We are all passionate about entrepreneurship and its transformative power in the world.
We are looking for a Senior Rails Developer to work along side our CTO (Ryan Garver). This person should have experience with TDD and modern Rails best practices. You will be our second developer pairing with our CTO and eventually helping to build a team as our company grows.
- Ruby on Rails
Development leadership experience is a plus.
We have a solid code base to start with thanks to the hard work by Pivotal Labs. An ideal candidate is someone who can code up a storm but also can facilitate sane TDD and agile practices with themselves and their teammates.
This is a full-time position located in the Bay Area. Please no consulting firms or off-shore providers.
To apply please send your information via http://profounder.theresumator.com/apply/C74ARA/
Jasmine bundled with RubyRacer
Jasmine is now optionally bundled with the RubyRacer gem. This lets you run Jasmine tests through Google’s V8 engine in a browser-less environment. Similarly, some Pivots paired Jasmine with Johnson and env.js to produce JazzMoney. Right now, JazzMoney is the only headless testing tool for Ruby that has DOM support, but I’m sure RubyRacer has that in mind. You can find JazzMoney here.
Does anyone know how to run specs with a certain name? We’re using RSpec to generate fixtures for our Jasmine tests and want those to be updated right before we run our Jasmine task.
You can set SPEC_OPTS with the ‘e’ flag and give it a string to match test names. Something like this:
rake spec SPEC_OPTS='-e "should generate a fixture"'
RubyMine is integrating with Pivotal Tracker! Beta version 2.5 lets you follow stories through the IDE’s task tool and tags your source control comments with the current tasks. It’s nice to see the title of your current story as you work. I’m excited to see what deeper integrations lie ahead. This screenshot shows what it looks like selecting a story through the menu item Tools > Task > Open…
In the the process of pulling assets out of a PDF we’ve noticed Preview crashes opening files larger than 45MB. Adobe Reader opens the same files without problems. Has anyone else had problems with Preview?
I ran into that issue and used the PDF optimizer in Acrobat to pull-out unnecessary markup and compress the images. That seemed to take care of the issue for Preview.
The Pivotal News Network has been going strong for six months (Pivots: talk to me if you’d like to share into the feed). Here are some highlights from May:
When starting any software project, there’s an age old argument: should we build something simple that solves our current problem or should we use an existing product that’s more complex, but more feature rich, since we know that’s where we’re going to end up in the future?
an oft neglected repercussion of building too much too quickly is that the extra functionality can calcify your product and make it very rigid. Releases become more complex, new features take longer to implement and bugs take longer to fix. You can find yourself a prisoner of your product, maintaining functionality and features that no one ( or very few ) people use. It can demoralize a engineering team, making them more and more susceptible to the nuclear option: the big rewrite.
I think the tendency to lean towards a more exhaustive solution upfront comes from a time when the effort require to change software was much higher than it is today. When systems were written in C, C++, Perl or even Java, making changes was a large undertaking. The thought of possibly throwing away chunks of code was nerve racking. It represented a huge investment in time and money. However, with todays rapid development languages and frameworks like Ruby/Rails & Python/Django, the investment required to create something, both in time and money, is rapidly shrinking.
Jeff [Patton]’s reply shocked me:
“The Ruby community cares about building high-quality apps, but doesn’t necessarily care about shipping high-value apps.”
Jeff went on to say that the Ruby community is obsessive about craftsmanship. This is a good thing, of course. We test. We write clean code. We take the time and care to build applications that are beautiful and do what our customers ask for.
Therein lies the rub: what customers ask for is rarely what they want, and almost never what they need. As Henry Ford put it, “If I had asked what people wanted, they would have said faster horses.” Or as I put it, your customer may pay you $1000 to deliver him a knuckle sandwich, but no amount of precision or strength training is going to leave you with a happy customer.
It turns out that constructing a high-quality application is not enough – you have to conceptualize and design an application that users will actually find useful. Doing this is every bit as difficult as constructing the software, if not harder. It requires a combination of research – generating new ideas from asking questions & identifying problems – and feedback – testing out ideas you’ve created. The Ruby & Agile worlds have been primarily focused on getting user feedback, without doing the all-important research.
Weeks ago, some people in the Ubuntu community got a bit disappointed with the distribution’s core team:
We are supposed to be a community, we all use Ubuntu and contribute
to it, and we deserve some respect regarding these kind of decisions.
We all make Ubuntu together, or is it a big lie?
We all make Ubuntu, but we do not all make all of it. In other words, we delegate well. We have a kernel team, and they make kernel decisions. You don’t get to make kernel decisions unless you’re in that kernel team. You can file bugs and comment, and engage, but you don’t get to second-guess their decisions. We have a security team. They get to make decisions about security. You don’t get to see a lot of what they see unless you’re on that team. We have processes to help make sure we’re doing a good job of delegation, but being an open community is not the same as saying everybody has a say in everything.
- from Velocity as a Goal
From my experience having velocity as a goal doesn’t make any difference to the motivation of the team which is often cited as the reason for referring to it as a target.
In all the teams I’ve worked on people are giving their best effort anyway so they can only really have an impact on the velocity by doing one of the following:
- Working longer hours
- Cutting corners on quality (by less testing perhaps)
- Finding a smarter way of working
In reality I haven’t noticed that people on the teams I’ve worked on pay that much attention to whether velocity is considered a target or not. People just do their job and we pretty much always have the same velocity each week regardless.
More popular shared items:
belongs_to associations can now automatically create back references each other, thanks to a Backport of :inverse_of from Rails 3 to rails 2.3.6. This allows us to keep our object graphs more correct and avoid situations where we have 2 copies of the same object because the object graph is walked in reverse. Here’s how to use it:
class Parent < ActiveRecord::Base
has_one :child, :inverse_of => :parent
class Child < ActiveRecord::Base
Ask for Help
A pivot asked “what is the current state of the art in scheduling recurring processes?”
The first-order answer was simply “cron”, but then the conversation got interesting.
Cron has a few downsides-
- Each task execution has to re-load the entire ruby/rails runtime, so, you pay a significant penalty in terms of startup time
- Crontabs often don’t get checked into source control, so there ends up being little visibility into which jobs are running when
One suggestion to solve the visibility problem was to use the whatever gem, which allows you to express your cron schedules in a ruby DSL that can easily be kept in source control.
A suggested alternative that eliminates cron altogether is resque-scheduler with resque.
The upsides with resque-based scheduling are that all your schedule logic is expressed in ruby, and you don’t pay the ruby/rails startup penalty for each worker.
The downside is that it adds additional operational infrastructure for you to manage (the resque workers and the redis server(s)).
We’ll be making some DNS changes that affect Pivotal Tracker this Saturday, May 29, at 10:00am PDT. We expect a fairly short outage, but for some users, Tracker may be unavailable for up to 6 hours.
Ask for Help
Identify and uploaded files
Running identify on uploaded files sometimes fails, because by the time identify gets hold of the file, the file extension has been lost (it has been written to
/tmp or the like).
The suggested workaround was to see if the filename specified in the
Content-Disposition header, if present, could be carried through to the temporary file.
Amazon has recently introduced a reduced-durabilty pricing tier for S3 storage, with significant discounts available to those who can live with 4 9′s versus 11 9′s of reliability. This seems like a win for things like thumbnails, which can easily be re-created from the originals on the off chance that they were actually lost by S3.
Rails 2.3.7 is out, but it doesn’t play nice with HAML just yet. Projects using HAML should avoid upgrading until those incompatibilities are ironed out.
- One of our clients had a large production issue due to a long-standing bug in Rails with case sensitivity.
Here’s the situation: Rails validates_uniqueness_of has a flag called :case_sensitive. This flag defaults to ‘true’, but can be flipped.
MySQL’s default collation is case-insensitive. As a result, queries will, in general, ignore case unless specifically overridden.
So one might imagine that setting :case_sensitive to false would be completely harmless in a standard MySQL application.
One would be wrong. Setting case_sensitive to false changes the query to lowercase the field in question, causing the MySQL database to ignore any indices it may have and turning the validates_uniqueness_of operation from something cheap and quick to something requiring a full table scan.
The open Lighthouse ticket on this issue is:
Ask for Help
“Any clever ways to catch out of bounds exceptions from Solr?”
This is a follow-up to yesterday’s Solr question. After some investigation, it looks like none of the major providers catch out of bound exceptions for very large numbers. Rather than instrumenting every Ruby call with validations to prevent these numbers from getting into Solr, are there any other brilliant ideas?
Goto File + line #: If you use ctrl-shift-N to go to a file, try typing in a line number after a colon, something like “my_file:30″. You’ll end up on that line.
Analyze stack trace: This tool lets you paste in an external stack trace, and gives you the ability to browse to all of the pieces of that stack trace.