-
Get a monthly update on best practices for delivering successful software.
edge case city: requirements and testing dates for HR business logic
We have an internal application that does staffing, time entry, and now Paid Time Off (PTO) accrual, scheduling and management. It is quite nice, as it has replaced three existing systems, and replaced a number of manual, tedious tasks. I started it last year, as our current system was very inefficient. It was a simple Ruby on Rails app that I was able to get working in a few weeks. Over time the functionality grew.
We recently added in PTO accrual and functionality to debit PTO time. In doing so in a test driven manner was great, as we could put all the edge cases. What we found was that many of the requirements were plentiful with edge cases. For instance, we get paid on the 15th or end of the month, unless that is a weekend. Then we get paid on a Friday - Except if that Friday is a holiday, then the previous Thursday - Except - if that is also a holiday.... So it is really the previous non-weekend, non-holiday on or before the 15th or end of the month. The same holds true to determine the beginning of the billing period. If the Monday is the 2nd, than for some operations the effective billing period start is Tuesday the third.... Ugh...
Our initial thoughts were filled with visions of lots of very similar tests for all contexts that do things depending on the start or end of a billing period. We didn't want to have lots of duplicate test code to test all edge cases, so we decided to extend the Date object to have a few helper methods to do the complicated logic in one place. We get the full range of the billing period start and end, and then trim off any holidays or weekends. What this did, was allow us to test the complicated logic in unit tests with a full set of complicated edge cases. We created many crazy examples of billing periods starting and ending on weekends, holidays, and holidays before and after weekends. This created a very robust set of methods to be used anywhere in the system.
We then mocked a call to each Date helper method everywhere in the system where it cared about what day it was, and weather it was the start/end of a billing period. We had only a few edge cases now: is it the true effective billing period start/end, or not. Our tests could then focus on the guts of what it actually did, regardless of the effective date.
This demonstrates how powerful unit testing is, and how mocking can really keep your tests concise. It made not only our code cleaner, but our tests cleaner. It reduced duplicate code, and increased our assurance that the code will function as designed.
That being said, it still doesn't change the fact that implementing HR logic in any language is a pain in the ass. I have worked on a couple of systems for accounting departments in the past, and their business requirements are much worse than HR. Dealing with job codes, general ledger accounts, etc can make your head spin. All I know, is that without TDD, this system would be buggy.

It's time to play "Ask A Tester Person", where I answer questions that I've gotten via email or otherwise about Rails Testing topics.
If you have a question for Ask A Tester Person, send it to railsprescriptions at gmail.com.
I've got two questions today:
Continue reading »
Topics: Ruby on Rails, tdd, Test Driven Development

Rails Test Prescriptions, the eBook put out by Noel Rappin, Director of Rails Development at Pathfinder, has been picked up by Pragmatic.
Congratulations to Noel - he's done a great job of furthering testing best practices in rails, and this is a great reward. As he said "I’m very excited by this. I’ve wanted to work with Pragmatic for as long as they’ve been publishing books, and I’m thrilled that this particular project will be able to get wider distribution and access to Pragmatic’s editorial expertise and skill."
* The current free “Getting Started with Rails Testing” ebook will continue to be available. If, at some time in the future, there’s a better Getting Started tutorial in the Pragmatic book, it may be offered as a replacement.
* The update site for current Rails Test Prescription owners will continue to be available for the foreseeable future.
* There will be one more official update to the current Rails Test Prescriptions, probably around the end of August. This will wrap up the chapter or two I’m working on, and tie up some other loose ends.
* After that, errata and information about changes to test tools will most likely be handled via this blog and an errata page on the rails test prescriptions site.
This is Noel's 4th book with a major publisher, following Professional Ruby on Rails, wxPython in Action and Jython Essentials. We're happy for Noel and happy to have him at Pathfinder.
Related Services: Ruby on Rails Development, Custom Software Development
Topics: rails testing, Ruby on Rails, Test, Test Driven Development, Testing
Here's a minor thing that bugs me all the time.
I'm writing a functional test:
should "do something functional" get :search,rder_id => @order.id, :user_id => @user.id # and so on end
The get call in that test simulates a browser request. Intuitively, you would (well, I would) expect this request to be identical to a request coming from the actual view, via a helper like link_to("search", :action => :search, . At least, you'd expect that parameters hash in the controller to be the same between the
rder_id => @order.id, :user_id => @user.id)
Makes sense, right? The testing call should set up the same environment as the actual call being tested. Continue reading »
Topics: rails testing, Ruby on Rails, tdd, Test Driven Development, Testing, wapcaplet
Dot, dot, dot, dot, dot -- tests are passing, looks like it's time for lunch -- dot, dot, dot, dot, F. F? F? But the code works. I know it does. I think it does. Why is my test failing?
One of the most frustrating times as a TDD developer is that moment when a test is failing and you don't know why, as opposed to the more normal case where the test fails as expected. Here's a grab bag of tips, tricks, hints, and thoughts to get us all through that difficult time.
Topics: Ruby on Rails, tdd, Test, Test Driven Development, Testing
What with upward of two people saying nice things about last week’s post, I’ve decided to keep going with part two of a look at some real testing code.
Most code-heavy tutorials show the code but not the tests — I’m doing the opposite here, and showing the tests, but not much of the code. Also, although I’m presenting these tests in chunks, you should realize that there was a lot of back-and-forth from Cucumber to tests to code and some backtracking, most of which I’ll spare you from having to wade through.
At the end of last week, I had run through the tests for spam-prevention code which worked by limiting the rate at which a user could send messages to other users of a particular social networking site. Cucumber was involved, and I think I went off on a tangent about writing lots of tests.
As sort-of promised in last week’s post, I’m going to work through a real-world test example, with an eye toward explaining how and why I tested the way I did. Hopefully, I’ll be able to do this at blog-post length. If not, well, there’s always next week.
This site, which was a legacy rescue, allows users to send messages to each other within the site without having to give away their other contact information. The problem is that nefarious spammer types were creating logins and immediately sending messages to large numbers of the user population, irritating them. After some deliberation, the client decided on a rate-limiting strategy, where a member could only send a certain number of messages in a day, and a new member could send even fewer messages a day. Messages above that point would require administrative action to unblock the user’s privileges.
Topics: rails testing, Ruby on Rails, Test Driven Development, Testing
It's been way too long since I blathered on about style issues. Today I'd like to talk about testing style. This article assumes you are already writing tests and already using something approaching a Test-Driven Development process -- I'm not here to argue about process, at least not today.
Today the topic is the actual construction of individual tests, how to name them, how to group them, where to get data from and the like.
I suspect I'll think of five more things right after I post this, so look for an update sometime in the future. The update will also address all the places where everybody tells me that I'm totally wrong.
Topics: rails testing, Ruby on Rails, Test Driven Development, Testing

Recently I have taken a bit of a detour into the world of telephony, working with Asterisk-Java, which by itself is a very valuable tool, and worth knowing a bit about if you are integrating a system with Asterisk. While it is a Java-based library, I am integrating it into a Grails application.
We have a fairly comprehensive suite of unit tests asserting that desired behaviors are triggered upon certain events initiated through the Event API. This is made even easier, as usual, with Groovy-- specifically on the testing front. Here I show two hypothetical test cases, followed by supporting code that works specifically with the Asterisk-Java classes...
Topics: asterisk, Grails, Groovy, telephony, Test Driven Development, unit testing
I mentioned last week that the RubyMine post was replacing what I had meant to write about. Well, this week we finally get to it...
It's been about ten weeks since I wrote about Cucumber the first time and the second time. Since then, I've continued to use Cucumber and now seemed like a good time to update some thoughts on how and why it seems to be working for us.
The big headline, of course, is that I'm still using it after ten weeks. I'm pretty quick to abandon tools that aren't pulling their weight, so just the fact that Cucumber is still in the toolbox means that despite the time that it takes to write Cucumber tests and step definitions, I'm finding the process of writing the tests and the tests themselves to be valuable.
Topics: cucumber, Ruby on Rails, Test Driven Development, Testing
I admit that cucumber is awesome. It apparently was the big thing at Rails Conf this year. I love that my BA can write the requirements, I can throw them into a feature file, and get feedback on my progress of the feature being done.
Cucumber is also an excellent choice for getting coverage on a legacy code base. Many of our clients have existing applications that were developed by cheap firms. They finally realize that they should have gone with a development company that writes automated tests, and works in a true agile manner. When initially looking at the code, we often get chills. There are usually zero tests. Most of the code sits in huge controller methods. We generally will use cucumber to start to get coverage for the features that the client wants changes to. We do write unit and functional tests, but we generally only assert the things we are changing. Over time, the unit and functional test coverage increases, and when we make changes we generally will refactor lots of the existing code base.
With that said, I have seen the use of cucumber on some of our projects change the way some developers code. They go from true TDD to crappy non-TDD. Many methods on the model don't have unit tests! How can we call this TDD?
I do admit that the functional tests can be a lot lighter, as you are getting coverage from the cucumber suite of tests. However, It doesn't mean that you can skip writing unit and functional tests.
This is how I incorporate cucumber into my development, while still maintaining 100% code coverage.
1. Write cucumber tests from the acceptance tests from the requirement
2. See all of the tests fail
3. Write unit tests, see them fail, write the code until the unit tests pass.
4. Write functional tests, see them fail, write code until the functional tests pass
5. Continue until I think the feature is fully implemented
6. Run the cucumber tests and see if anything still fails. - Add unit/functional tests to address failing cucumber tests. Once all tests pass, run the test coverage to ensure there are no holes (this generally doesn't happen, as I am practicing TDD).
Related Services: Ruby on Rails Development, Agile Development, Custom Software Development
Topics: cucumber, Test Driven Development, Testing, Unit Tests
My cucumber obsession continues unabated. I've spent a lot of the last week adding Cucumber to projects, writing about it in a very long section for the Rails Test Prescriptions book, and generally trying to figure out how to use this tool, not to mention trying to figure out why this tool has been so interesting to me this week.
Some follow-up thoughts since last week's post.
Continue reading »
Topics: Ruby on Rails, tdd, Test Driven Development, Testing
An consistent nuisance problem when testing Rails applications is the "unit test gap". This happens when the model test passes and the controller test passes, but the application as a whole fails because there's a mismatch between the output produced by the model and the input given to the controller test. In theory, Rails integration tests can solve this problem, but they aren't really designed for it, and nobody uses them much anyway.
An easy-to-use tool that solves that end-to-end testing would be great. Somebody should really write a blog post about that.
So, as I was saying. We continually run into an issue with our clients over defining requirements at the level that developers need to keep going, without getting bogged down in long stretches of design. There's a big gap between "users should be able to upload photos to their pages" and all the different details of permissions, validation and the like than need to be answered at some point. The Agile process suggests that those requirements be created as closely as possible to the code, which leads to the question of how best to keep the customer in the loop while the developers need these decisions to be made.
An easy-to-use tool that lets users read or create requirements that developers can build from and run as acceptance tests would be great. Somebody should definitely write a blog post about that.
Which brings us -- finally -- to Cucumber, a tool for creating automated acceptance tests. It's flexible enough to solve both problems. It can be used as a developer tool to drive regular TDD testing, and as a client tool for managing requirements.
Topics: cucumber, Ruby on Rails, tdd, Test Driven Development, Testing
Rails Test Prescriptions: Keeping your Application healthy is now on sale. This is a beta, partial release.
Rails Test Prescriptions is a comprehensive guide to testing your Rails application, covering both the mechanics of writing tests and the style for writing good and useful tests.
I'm excited to be publishing this electronically in a way that allows me to keep the book up to date as Rails changes over the upcoming months and years. Your $9 purchase entitles you to all updated versions for the life of the book.
Continue reading »
Topics: Ruby on Rails, tdd, Test Driven Development, Testing
All software has bugs. I don't care if you're Apple, Microsoft, IBM, or a smaller, leaner ISV. Your software has bugs in it. Once you accept this fact, that into each software product a little crap must fall, it becomes clear that what differentiates one software development organization from another is how they manage those bugs. What do you do to prevent them in the first place, find them, fix them, measure them, celebrate their squashing?
Most of the developers at Pathfinder Development are old hands. We've been around the block a few times. We've worked on quite a number of software projects over the years. We've all gravitated toward agile development not because it's the latest buzzword, or because it feels so good (though it does when it's done right), but because everything else feels so bad.
Take testing, for example. Testing girds you, the product manager, for the moment of truth -- deploying or shipping a new release. In the monolithic or waterfal processes, we would often wait until the end, after all of the development was done to "QA" the application. Often you'd throw in some performance testing to see if this monstrosity you'd just built would actually handle the load you were going to throw at it.
After weeks or months of testing, fixing, hoping, praying and integrating, you'd finally deploy. Odds are you'd ship with some pretty serious bugs. But the quality of the software, in terms of bugs and errors, was pretty poor and the expense and effort of the developers fixing the bugs was akin to the contractor applying spackle to a drywall that was more hole than whole.
Let me go through some of the testing we do today, what the previous alternative was, and what the benefit for your product is.