Posts in "Testing"

Check Alert Message with Poltergeist or Capybara Webkit

Use accept_alert to get the alert message.

  • Poltergeist ignores alerts/confirms by default(source)
  • Poltergeist has had support for Capybaras modal api since September 2015( source)

That means you can same syntax for Poltergeist or capybara-webkit.

expect(accept_alert).to eq("Javascript alert message")

# or with block syntax

# will fail if alert message doesn't match
accept_alert("Javascript alert message") do 
  # next expectation
end

The first one expect(accept_alert).to reads a bit weird, but that's the return value of accept_alert.

June 28, 2016 capybara, Testing, poltergeist

Add binding.pry breakpoint dynamically with pry-byebug

When debugging if you want to check at some lines where you forget to put the binding.pry, you could use some help from pry-byebug's break points feature.

You can set and adjust breakpoints directly from a Pry session using the break command:
https://github.com/deivid-rodriguez/pry-byebug#breakpoints

break SomeClass#run            # Break at the start of `SomeClass#run`.
break app/models/user.rb:15    # Break at line 15 in user.rb.
...

Please bear with me with this example as a showcase.

scenario "Guest can't view draft post" do
  post = create(:post, title: 'Vim', published_at: nil)
  binding.pry
  visit post_path(post)
  expect(page).not_to have_content('Vim')
end

Suppose you put the first binding.pry there to check the creation of post, then somehow you also want to check what's going on in the controller, normally you would stop/finish the spec and drop the binding.pry to controller and rerun the spec. With pry-byebug you could set the breakpoint in the runtime: when the execution is stopped before the visit post_path(post)

[1] pry(#<RSpec::ExampleGroups::Posts>)> break PostsController#show

  Breakpoint 1: PostsController#show (Enabled)

  10: def show
  11: end

Now the breakpoint is set, if you continue the spec then it'll stop at the posts#show action.

This is also very useful when you check some codebase you're not familiar with like gems, during the debugging you also want to check some local variables inside a block or so, with the break command now you don't need to make changes to the library and restart your rails server.

June 06, 2016 Testing

Notes on Let's Make Testing Fun Again

The talk

Let's Make Testing Fun Again at WindyCityRails 2012 | Lanyrd

Communication

Tests give you about the code. This happens over time, where you find that tests have become hard to write, the tests are becoming complicated and bogged down.

Rather than use it as an opportunity to blame the test or to blame testing, you should use it as an opportunity to learn something about your code, that there is a dependency that could potentially be simplified, or something you could be doing better.

Keep relevant setup close

This is something that "relative good"(in terms of "absolute good"). It's generally good to keep the setup of your tests close to the tests where it is.

What you want to avoid is the case where some sort of before setup way at the top of the file and you have stuff, and more stuff, and more stuff, and eventually in the end, what's the @user.name? I don't remember.

An Example


describe User do
  before do
    @user = Factory.build(:user)
  end

  # and more stuff

  # and more stuff

  it "uses the user" do
    @user.name.should == # i don't remember
  end
end

This is where you see sometimes people say "You should never have setup outside your original test".

What to do about duplications and complicate shared setups

I think a lot of times if you need a complicated setup to test code, that often means your code is too complicated you need to start working out to move your dependencies. I tend to have a higher tolerance for duplication in my tests than I do in my regular code, specifically because I'm more interested in having the communication close, and less interested in maybe being clever about extracting setups in my tests. Sometimes I do if there's a piece of stuff that's really tightly coupled, and I can give it a descriptive enough name that I still feel like I have the benefit of keeping the setup close in the actual test.

Test Simple Values

By using literal in check, when the spec fails, the error message is much easier to understand.

Spy, don't mock

A jasmine
test example.

var cheeseburger = {
  cheeses: function() {
    // Ajax call to cheese server
  }
};

it('spies on the cheese server', function() {
  spyOn(cheeseburger, 'cheeses');
  cheeseburger.cheeses();
  expect(cheeseburger.cheeses).toHaveBeenCalled();
});

  • Readability advantage
  • Easy to find where actually fails

BTW, if in spec, we need write like this:


it 'spies on the cheese server' do
  # in the reversed order
  cheeseburger.should_receive(:cheeses)
  cheeseburger.cheeses
end

More about Spy on Ruby and Rails

thoughtbot/bourne gem can let you have the rspec-like test spies syntax.

Spy vs spy, good explanation on what is test spy the benefit of it.

What Do We Love?

These are quite frank and interesting questions.

  1. Do we still love writing tests?
  2. Or do we just love having written tests?
  3. Or do we just love saying that we've written tests?
June 01, 2013 Testing

Notes on Fast Test, Slow Test

Recently I got lots of inspirations and thoughts on how to write good tests. Thanks to Cookpad, the company I’m working on, I get the chance to work on a very large scale rails app. But it also introduces me to some very bad tests. Sometimes I found myself so difficult to add any spec, as it needs lots of extra efforts to make the fixture data, also one model got too many dependencies and collaborators, etc. I know it’s wrong, the code smells, just don’t know where to start.

So when I watched this video “Fast Test, Slow Test” by @garybernhardt, who also runs DestroyAllSoftware screencast, I found it very helpful and wanted to take some notes on it.

Three Goals in Testing

  • Prevent Regression
  • Prevent Fear
  • Prevent Bad Design

How to Fail in Testing

  • Selenium as primary testing
  • “Units Test” are too large
  • Fine-grained tests around legacy code

What you’re saying here is that we acknowledge that this code sucks, so we’re going to go in and write tight tests around it that solidifies interface and just bake the badness forever. This is the worst way to do unit testing, go in your legacy system and write test around bad code.

Too many dependencies in test

You end up with a test suite where it tends to either completely succeed or completely fail. It doesn’t give you any fine-grained feedback about what has actually gone wrong it just tells you you broke something. And you are left to dig these stack traces. In the ideal test suite you don’t have to dig through stack traces because ideally once test fails it will tell you exactly was broken (of course you never achieve that)

More than 8 lines for a model test

I would ask myself why do I need to setup so much of the world to test this one small piece of behavior. That causes me to decompose it which causes better system design.

10% System/Acceptance Test, 90% Unit Test

(in terms of test cases, not lines of code)

That applies to mostly object heavy system like web app, that have a lot of logic and not a lot of boundaries.

Advice on models that very tied to database

Question

If you're working with model objects that they're very tied to the database specifically things like you have to save that one object before you can associate with the other object and that means hitting the database. What's your advice in terms of writing fast unit test?

Answer

Take all of that behavior that's on your model objects and pull out of their into service classes that are stateless, that interact with the model objects. So view calls a service, service contains the intelligence and the service manipulates the model objects.

You can still have methods on your model objects do things like wrap specific queries in class methods, or wrap specific mutations when multiple fields are commonly manipulated together.

It's okay to have those on your model object and then have the service use those but if you pull the behavior of the system out into the service, and you control the boundary between the service in the model by those methods you've written on the model, then you can mock out more easily and safely.

May 30, 2013 Testing