Skittlish Tips'n'Tricks

  • Change the classes for the body tag to set your default site style. also change these in the app.js file (line 66).
  • Remove the scripts and the #options div if you don't want the option switcher.
  • The top menu shows the home section and the sections that are not blogs.
  • Email me at evil@che.lu if you have any questions.
  • Happy hacking!

Performance

written by tinney on July 27th, 2007 @ 08:28 PM

- is what you use to pay for user friendliness

Mocking 'render :partial =>'

written by tinney on May 22nd, 2007 @ 10:32 PM

Rspec BoF, at RailsConf 2007, mocking the rendering of a partial from inside a view spec was said to be possible by mocking the call to 'render_partial'.

However, trying to implement the pattern we found that render_partial has been deprecated. We ended being able to do this:
describe "Showing a Readout" do
  it "should render the readout partial to the page"
    response.template.should_receive(:render).with(:partial => "readout").and_return("readout_partial_rendered")
    render "/readouts/show" 
    response.should have_text("readout_partial_rendered")
  end
end
Mocking partials allows for testing of views separately and increases test readability.

after(:expects) - Addressing BD stateless code

written by tinney on May 13th, 2007 @ 10:41 PM


Rspec & Mocking stateless code leads to this:

before(:each) do
  @lime_in_the_coconut = "Mix it all together"
  @coconut_juice = "juice of the coconut"
  @lime_juice = "juice of the lime"

  @lime_mock = mock "lime"
  @coconut_mock = mock "coconut"
  @mixer_mock = mock "mixer"
  @juicer = Jucer.new(@mixer_mock)

  @lime_mock.should_recieve(:squeeze).and_return(@lime_juice)
  @coconut_mock.should_receive(:squeeze).and_return(@coconut_juice)
  @mixer_mock.should_receive(:mix).with(@lime_juice, @coconut_juice).and_return(@lime_in_the_coconut)
end

it "should return them mixed all together" do
  @juicer.mix_it_all_together(@coconut_mock, @lime_mock).should == @lime_in_the_coconut
end

Adding after(:expects) could address the non-behavior driven test:

before(:all) do
  @lime_in_the_coconut = "Mix it all together"
  @coconut_juice = "juice of the coconut"
  @lime_juice = "juice of the lime"

  @lime_mock = mock "lime"
  @coconut_mock = mock "coconut"
  @mixer_mock = mock "mixer"

  @juicer = Jucer.new(@mixer_mock)
end


expect "it to squeeze the lime" do
  @lime_mock.should_recieve(:squeeze).and_return(@lime_juice)
end

expect "it to squeeze the coconut" do
  @coconut_mock.should_receive(:squeeze).and_return(@coconut_juice)
end

expect "it to mix the coconut and the lime juice" do
  @mixer_mock.should_receive(:mix).with(@lime_juice, @coconut_juice).and_return(@lime_in_the_coconut)
end

after(:expects) do
  @juice = @juicer.mix_it_all_together(@coconut_mock, @lime_mock)
end

it "should mix it all together" do
  @juice.should == @lime_in_the_coconut
end

  1. before(:all) - Setup variables
  2. expects - Setup the mocks
  3. after(:expectations) - run the code after mocks are setup
  4. it/specs - normal expectations
  5. Teardown mock verifies - expectations are checked and fail if mock expectation were not satisfied

If our mock fails to verify the expect text could be raised giving you a better idea of what happened. Generally order does not matter for mocking but a expect(:first) parameter could be introduced to satisfy order critical testing

Rspec - context & state

written by tinney on May 8th, 2007 @ 12:13 AM

From our current code base:
describe "A GroupsController" do
  it "should let you create a new group and then redirect to the groups url and set the flash to 'Created new group'" do
  end
end
Testing a sword that has 2 directly related methods was a great example. When the methods do not relate is when the pattern breaks down, imho. I would argue that we are losing test clarity by keeping method names out of the context(s).
describe GroupsController, "#creating a valid group" do
  it "should create a new group"
  it "should redirect to the groups url"
  it "should set the flash to 'Created new group'
end
Calling a method can be a context. Starting a car for example is a state that cars can hold. I do agree that sharp? and rusty? are not states and putting them in the context was stretching the limits of that example.

Rspec Styles

written by tinney on May 3rd, 2007 @ 06:51 PM

Recently a co-worker blogged about the 2 different styles of Rspec BDD him and another co-worker have been going back and forth over. Here is where I stand: My solution to the sword:
describe "sharp? with a new sword" do
    before(:each) do
        @sword = Sword.new(:status => 'new')
    end

    it "should tell us that it is sharp" do
        @sword.sharp?.should == true
    end
end

describe "sharp? with a used sword" do
    before(:each) do
        @sword = Sword.new(:status => 'used')
    end

    it "should tell us that it is not sharp" do
        @sword.sharp?.should == false
    end
end  


The describe/context when combined with the class name would become "Asking a new sword if it's sharp?". This style allows the sharp? methods to be clearly stated in a few areas. This still allows you to practice TDD. Each branch in "sharp?" gets its own context. If you see to many contexts for a certain method it's a good time to move functionality out and into another class, presenter or helper.

I tried Kurts idea for a while. But found I often became lost as to what describe/context should contain my specify/it. I then decided that the overhead of a few extra contexts what nothing compared to the benefit and clarity that my tests gained by putting the method names in the describe/context.

Mocking - What to test?

written by tinney on April 12th, 2007 @ 10:14 AM

What do we want to test in this method?

class RecordCreator
  def create_new_record(user, name)
    record = Record.new
    record.group = user.group
    record.name = name
    record.save!
  end
end

With out mocks

def test_create_new_record_should_create_a_new_record_setting_user_group_and_saving
  record_creator = RecordCreator.new
  user = User.create!(:group => Group.new)
  record = record_creator.create_new_record(user, "My New Record's Name")
  assert_equal record.name, "My New Record's Name" 
  assert_equal record.group, user.group
  assert !record.new_record?
end

For some this might be fine. Either way there are a few things wrong with this test. The most obvious is we’re assuming we know everything the name= method does on record. What if it set the name and stripped out ’ replacing them with the html symbol. Our tests would then break.

  1. Hits the DB when it doesn’t have to, assuming save! and AR are defaults
  2. Tests name=, group= and user method on record
  3. Tests group and name getters on record

With Mocks

def test_create_new_record_should_create_a_new_record_setting_user_group_and_saving
  user_mock = mock "user" 
  user_mock.stubs!(:group).and_return("The Group")

  RecordCreator.should_receive(:new).and_return(record_mock)
  record_mock.should_receive(:group=).with(user.group)
  record_mock.should_receive(:name=).with("My New Record's Name")
  record_mock.should_receive(:save!)
  record = record_creator.create_new_record(user, "My New Record's Name")

  #Go Start Test
  assert_equal record, record_mock, "create_new_record should return back created record" 
end

Now Why is this better?

We’re not hitting the DB

Your tests will be come faster.

Creating users isn’t our problem

If creating a users changes our test won’t break. Now the flip side if group ever goes away from user your tests will still pass but your code will break. Showing the importances of integration tests

name= can do what ever we want

The side effects of name=’s will no longer break our test.

One last thing

We used stub! for getting the group call out of user. I find stub! to be a perfect fit for just such an problem. First, you don’t have to worry how many times user.group was called. Second, you still prove that what ever user.group returned you used. Last, it cleans up your test! with(user.group) looks much better then with(@group) and one less @var has to be better.

Programmer costs

written by tinney on April 11th, 2007 @ 10:45 PM

I find it to be a myth that businesses save on costs by forcing programmers to use their own computers. After watching distractions arise again and again it became clear to me that personal computers should be left out of the work place.

  • IMing
  • RSS readers
  • Personal events calendar
  • Personal Email (1 time an hour is enough)
  • House keeping
  • Downloads….

I’m not saying I don’t do this. Just the other day I

  • Cleaned up the icons on my desktop
  • Downloaded a new background
  • Updated my gmail settings to download into Mail.app
  • Read about the “Girls gone Wild” guy being arrested for saying “Judge gone wild” in court

I think pair programming suffers the most. I no longer feel as though I have the ability to continue if my pair leaves the room. I almost feel as though I have to stop looking at the code and move off the computer. You could argue that you shouldn’t be writing code with out a pair there but lets face it looking at a computer screen or problem and writing code are 2 different things.

If you’re going to force your programming staff to use their own computers at least have the common decency to buy them back up drives and pay the 80 dollars a year to insure their machines so that when they’re taking them on the subway to and from work they are protected. Possibly encourage alternative accounts if pairing and most of all clear your history I don’t need to see your fetishes.

The Rails of Demeter

written by tinney on April 1st, 2007 @ 12:21 AM

Recently we’ve been moving our application to use rspec and more mock based testing. My boss constantly talks about code smells. Mocks allow you to get the stink out quick. As soon as it becomes a pain in the ass to test with a mock you know you’ve got something going on that’s bad. Lately I’ve found the biggest culprit is the Law of Demeter. Let’s review:

Law of Demeter with an object O should only access # O itself # M’s parameters # any objects created/instantiated within M # O’s direct component objects

As I started testing our view I was tricked. The first sign was the 5 NEW mocks that I had to create just to test roughly 10 lines of code. Which would be fine if the mocks weren’t chained:

a_mock.should_receive(:b).and_return(b_mock) b_mock.should_receive(:c).and_return(c_mock) c_mock.should_receive(:d)....

you get the point…

After pulling everything out I found this little turd..

@run.assay.readout_definitions.hit_definitions.color

Ugh!

Testing In Rails

written by tinney on March 27th, 2007 @ 10:57 PM

All rails projects test something, test truth at the minimum. Reading through this post i saw this:

...does this testing make any sense? I mean, validation is a part of ActiveRecord, “which is pretty well tested already”

Testing 101

def sum(value_1, value_2)
  return value_1 + value_2
end

def test_sum
  assert_equal sum(2,2), 4
end

What are you really testing?

We're not testing the '+' operator but rather everything around it. Think of validates_presents_of as your + operator. Now we need to test everything around it.

  1. You're testing that you spelled it correctly
  2. You're testing it works the way you say it does (+ takes 2 numbers)
  3. You're making yourself think before you code (not writing code you do not need)
  4. You're making others think before they remove (forcing a broken test or behavior if something is removed)
  5. You're making your job easier when DHH takes away validates_presents_of and replaces it with validates_syntax_sugar

Just like we REALLY don't care what the value is returned from by SUM so long as '+' happens. return value of "value_1 + value_2".

Mocking

If the sum method had to use another object to do the + I could then remove the result, or at least the logic of what 2+2 really is, from my test.

def sum(value_1, value_2)
  return Operators.add(value_1, value_2)
end

specify "sum should return the added values" do
  Operators.should_receive(:add).with(2, 2).and_return(5)
  sum(2, 2).should == 5
end

My test would no longer have to verify that "2 + 2" is really 4. It would instead be verifying that I wanted to return back from the method the result of "2 + 2" Because why would you test something that "is pretty well tested already”

Final Note

Another comment from this blog says: "I think testing simple validations is a bit much. I definitely don’t do it that much in OSS projects :) It’s just a judgment call you have to make I suppose. Do you have the time to test every single line?"

If you don't think you have the time to test every single line then maybe you shouldn't be writing that line. Because if you don't have time to write that line of code I'm positive you're not going to have the time to maintain it.

ActiveRecord.#{attribute}_before_type_cast

written by tinney on March 5th, 2007 @ 09:50 PM

The problem:

A user enters an incorrect date into your form. After a submit the form returns back to with an error on the date field but their original value is gone.
my_model.date_field = "tomorrow" #set some invalid date
puts my_model.date_field  #returns nil

The solution:

my_model.date_field_before_type_cast

Now instead of the user seeing a blank field they can see their original value with an error message. Letting them know that "tomorrow" is not a valid date.

my_model.date_field = "tomorrow" #set some invalid date
puts my_model.date_field_before_type_cast  #returns "tomorrow" as a string

Rails Delegate

written by tinney on January 23rd, 2007 @ 11:39 PM

Rails introduced the delegate function. Which allows you to delegate a method call. However if the delegated object has not been set your code will raise:
NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.hot
    (__DELEGATION__):2:in `hot'
delegate :hot, :to => :cookie
Which should replace this:
has_a cookie
def hot
  self.cookie.nil? ? nil : self.cookie.hot
end
But instead falls a little short and would replace the following
def hot
  self.cookie.nil? ? nil.hot : self.cookie.hot
end

Mac Book Pro Hard Drive Upgrade

written by tinney on January 21st, 2007 @ 06:29 PM

I recently upgraded my hard drive to a 160GB HITACHI.

The upgrade went well except for one small detail. Most hard drives have a small hole in the outer casing to allow the hard drive platters to breathe.

Hitachi just happens to have its hole conveniently placed in the same area where the Mac's blue tooth cable adheres itself to the hard drive.

As I gave up in my attempt to gain more slack on the bluetooth cable, I ignored the "Do not cover this hole" warnings, clearly marking the now well covered air hole. Like the beached whale Seinfeld episode: "Titleist.. Hole In One".

Hard Drive:
Hitachi Travelstar 5K160 HTS541616J9SA00

Options:

Size

Colors