SkillAgentSearch skills...

Wrong

Wrong provides a general assert method that takes a predicate block. Assertion failure messages are rich in detail.

Install / Use

/learn @sconover/Wrong
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

"Feels so right, it can't be Wrong"

Someone is Wrong on the Internet

Maintained by: Alex Chaffee http://alexchaffee.com

Abstract

Wrong provides a simple, general assert method that takes a block, and understands the code inside it, providing verbose failure messages for free.

The Wrong idea is to replace assert_equal and all those countless assert\_this, assert\_that, should\_something library methods which only exist to give a failure message that's not simply "assertion failed". Wrong replaces all of them in one fell swoop, since if you can write it in Ruby, Wrong can make a sensible failure message out of it.

We'd very much appreciate feedback and bug reports. There are plenty of things left to be done to make the results look uniformly clean and beautiful. We want your feedback, and especially to give us cases where either it blows up or the output is ugly or uninformative.

Inspired by assert { 2.0 } but rewritten from scratch. Compatible with Ruby (MRI) 1.8, 1.9, and JRuby 1.5.

Installation

gem install wrong

We have deployed gems for both Ruby and JRuby; if you get dependency issues on your platform, please let us know what Ruby interpreter and version you're using and what errors you get, and we'll try to track it down.

Usage

Wrong provides a simple assert method that takes a block:

require "wrong"   # or require "wrong/adapters/rspec" (see below)

include Wrong

assert { 1 == 1 }
 ==> nil

assert { 2 == 1 }
 ==> Expected (2 == 1), but 2 is not equal to 1

If your assertion is more than a simple predicate, then Wrong will split it into parts and show you the values of all the relevant subexpressions.

x = 7; y = 10; assert { x == 7 && y == 11 }
 ==>
Expected ((x == 7) and (y == 11)), but
    (x == 7) is true
    x is 7
    (y == 11) is false
    y is 10

--

age = 24
name = "Gaga"
assert { age >= 18 && ["Britney", "Snooki"].include?(name) }
 ==>
Expected ((age >= 18) and ["Britney", "Snooki"].include?(name)), but
    (age >= 18) is true
    age is 24
    ["Britney", "Snooki"].include?(name) is false
    name is "Gaga"

And a companion, 'deny':

deny{'abc'.include?('bc')}
 ==> Didn't expect "abc".include?("bc")

More examples are in the file examples.rb http://github.com/alexch/wrong/blob/master/examples.rb

There's also a spreadsheet showing a translation from Test::Unit and RSpec to Wrong, with notes, at this Google Doc. (Ask alexch@gmail.com if you want editing privileges.)

And don't miss the slideshare presentation.

Helper methods

All these helper methods are provided if you do include Wrong.

rescuing

There's also a convenience method for catching errors:

assert{ rescuing{raise "vanilla"}.message == "chocolate" }
 ==>
Expected (rescuing { raise("vanilla") }.message == "chocolate"), but
    rescuing { raise("vanilla") }.message is "vanilla"
    rescuing { raise("vanilla") } is #<RuntimeError: vanilla>
    raise("vanilla") raises RuntimeError: vanilla

capturing

And one for capturing output streams:

assert { capturing { puts "hi" } == "hi\n" }
assert { capturing(:stderr) { $stderr.puts "hi" } == "hi\n" }

out, err = capturing(:stdout, :stderr) { ... }
assert { out == "something standard\n" }
assert { err =~ /something erroneous/ }

close_to?

If you want to compare floats, try this:

assert { 5.0.close_to?(5.0001) }   # default tolerance = 0.001
assert { 5.0.close_to?(5.1, 0.5) } # optional tolerance parameter

If you don't want close_to? cluttering up Float in your test runs then use include Wrong::Assert instead of include Wrong.

close_to? also works on Times, Dates, and DateTimes. The default tolerance of 1 msec may be too small for you, so you might want to do something like:

assert { user.created_at.close_to?(Time.now, 2) }  # or 2.seconds

close_to? also works inside RSpec should statements with the magic be matcher, e.g.

5.should be_close_to(6)

d

We also implement the most amazing debugging method ever, d, which gives you a sort of mini-wrong wherever you want it , even in production code at runtime:

require 'wrong'
x = 7
d { x } # => prints "x is 7" to the console
d { x * 2 } # => prints "(x * 2) is 14" to the console
d("math is hard") { 2 + 2 } #=> prints "math is hard: (2 + 2) is 4"

d was originally implemented by Rob Sanheim in LogBuddy; as with Assert2 this version is a rewrite and homage. You may also enjoy g by jugyo.

Remember, if you want d to work at runtime (e.g. in a webapp) then you must include Wrong::D inside your app, e.g. in your environment.rb file.

eventually

If you care that something is going to be true soon, but maybe not right now, use eventually.

eventually { night? }

It will keep executing the block, up to 4 times a second, until either

  • the block returns true(ish)
  • 5 seconds elapse

If the block raises an exception, then eventually will treat that as a false and keep trying. The last time it fails, it'll raise that exception instead of a mere AssertionFailedError. That way, the following are all possible:

eventually { false }
eventually { assert { false } }
eventually { false.should be_true }  # in RSpec

and you should get the expected failure after time expires.

You can also send options to eventually as hash parameters.

eventually(:timeout => 10) { false } # keep trying for 10 sec
eventually(:delay => 1) { false }    # try every 1.0 sec, not every 0.25 sec

(For now, eventually is in its own module, but you get it when you include Wrong. Maybe it should be in Helpers like the rest?)

Test Framework Adapters

Adapters for various test frameworks sit under wrong/adapters.

Currently we support

  • Test::Unit - require 'wrong/adapters/test_unit'
  • Minitest - require 'wrong/adapters/minitest'
  • RSpec - require 'wrong/adapters/rspec' (now supports both 1.3 and 2.0)

To use these, put the appropriate require in your helper, after requiring your test framework; it should extend the framework enough that you can use assert { } in your test cases without extra fussing around.

For example:

require "test/unit"
require "wrong/adapters/test_unit"
class PlusTest < Test::Unit::TestCase
  def test_adding_two_and_two
    assert { 2 + 2 == 4 }
  end
end

require "rspec"
require "wrong/adapters/rspec"
describe "plus" do
  it "adds two and two" do
    assert { 2 + 2 == 4 }
  end
end

Piecemeal Usage

We know that sometimes you don't want all the little doodads from a library cluttering up your namespace. If you don't want to do

require 'wrong'
include Wrong

then you can instead require and include just the bits you really want. For example:

require 'wrong/assert'
include Wrong::Assert

will give you the assert and deny methods but not the formatters or rescuing or d or close_to?. And if all you want is d then do:

require 'wrong/d'
include Wrong::D

To summarize: if you do require 'wrong' and include Wrong then you will get the whole ball of wax. Most people will probably want this since it's easier, but there is an alternative, which is to require and include only what you want.

And beware: if you don't require 'wrong', then include Wrong will not do anything at all.

Gotcha: Side Effects Within the Assert Block

Be careful about making calls within the assert block that cause state changes.

@x = 1
def increment
  @x += 1
end

assert { increment == 2 }
assert { increment == 2 }
 ==> Expected (increment == 2), but
     increment is 5

The first time increment fires the result is 2. The second time the result is 3, and then Wrong introspects the block to create a good failure message, causing increment to fire a couple more times.

Confusing, we know! A few patient Wrong users have hit this when the assert involves ActiveRecord write methods like #create! and #save.

The fix: introduce a variable:

value = increment
assert { value == 2 }
assert { value == 2 }

Apology

So does the world need another assertion framework? In fact, it does not! We actually believe the world needs fewer assert methods.

The Wrong idea is to replace all those countless assert_this, assert_that, should_something library methods which only exist to give a more useful failure message than "assertion failed". Wrong replaces all of them in one fell swoop, since if you can write it in Ruby, Wrong can make a sensible failure message out of it.

Even the lowly workhorse assert_equal is bloated compared to Wrong: would you rather write this

assert_equal time, money

or this

assert { time == money }

? The Wrong way has the advantage of being plain, transparent Ruby code, not an awkward DSL that moves "equal" out of its natural place between the comparands. Plus, WYSIWYG! You know just from looking at it that "equal" means ==, not eql? or === or =~.

Moreover, much like TDD itself, Wrong encourages you to write cleaner code. If your assertion messages are not clear and "Englishy", then maybe it's time for you to refactor a bit -- extract an informatively named variable or method, maybe push some function onto its natural object a la the Law of Demeter... Also, try not to call any methods with side effects inside an assert. In addition to being bad form, this can cause messed-up failure messages, since the side effects may occur several

View on GitHub
GitHub Stars435
CategoryDevelopment
Updated4mo ago
Forks31

Languages

Ruby

Security Score

92/100

Audited on Nov 6, 2025

No findings