Posted at

should API Reference覚書

More than 3 years have passed since last update.


should.js

sholudはobject自身を拡張して、sholudメソッドを追加して実装されている。


テストする対象が、nullやundefinedの時はオブジェクトではないからshouldを呼ぶと、エラーになってしまう。


null、undefineでshouldを使うと...

1) Calculator null should be a 'null':

TypeError: Cannot read property 'should' of null


2) Calculator undefined should be an 'undefined':
TypeError: Cannot read property 'should' of undefined




Chains

全てのアサーションはshould.jsラッパーオブジェクトを返ので、チェインすることができる。  

「to, be, been, is, that, which, and, has, have, with, at, of, same」はチェイン可能なgetterとして提供されていて、テスト機能は提供していないみたい。


.not

アサーションを否定します。


.deep

deepフラグを設定した後で、equalとpropertyアサーションで使われる。


.any

anyフラグを設定した後、keysアサーションで使われる。(allフラグの反対)


.all

allフラグを設定した後、keysアサーションによって使われる(anyフラグの反対)


.a(type) / .an(type)

a、anアサーションは言語の接続または、値の型を検証することのどちらかで使うことができるエイリアス。

# typeof

# string型かテストする
# → string型なのでテストは成功する
'test'.should.be.a 'string'

# object型か検証する
# → オブジェクト型なのでテストは成功する
{ foo: 'bar' }.should.be.an 'object'

# language chain
# anがchainとして使われている。
person = new Person('test', 100)
person.should.be.an.instanceof Person


.include(value) / .contain(value)



  • @param{ Object | String | Number }obj


  • @param{ String }message_optional_

includeとcontainのアサーションはいずれかの配列内のオブジェクトまたは、文字列中の部分文字列を検証する。言語の接続chainとして使用することもできるできます。

# 配列の中に2が含まれていることをテストする

# → 2が含まれているのでテストは成功する
[1, 2, 3].should.include 2

# 文字列"footer”の中に部分文字列"foor"が含まれていることをテストする
# → 部分文字列"foo"が含まれているのでテストは成功する
'footer'.should.contain 'foo'

# オブジェクトの中にfooというプロパティが含まれているかテストする
# → オブジェクトの中にfooとういプロパティが含まれているのでテストは成功する
{ foo: 'bar', hello: 'universe' }.should.include.keys 'foo'


.ok

真であること検証する。

# 真であることをテストする

# → テストは成功する
true.should.be.ok

# 真であることをテストする。
# → 偽であるため、テストは失敗する。
false.should.be.ok

否定で使うと、

# 真であるべきでないことをテストする

# → テストは成功する
false.should.not.be.ok

# 真であるべきでないことをテストする
# → 真であるため、テストは失敗する
true.should.not.be.ok


.true

chainしたオブジェクト === trueであるとを検証する。

# 真であることをテストする。

# → テストは成功する
true.should.be.true

否定で使うと、

# 真であるべきでないことをテストする

# → 偽であるため、テストは成功する
false.should.be.not.true


.false

chainしたオブジェクト === trueであるとを検証する。

# 偽であることをテストする

# → テストは成功する
false.should.be.false

否定で使うと、

# 偽であるべきでないことをテストする

# →真であるため、テストは成功する
true.should.be.not.false


.exist

対象がnullでもundefineでもないことをテストする

foo = 'hi'

# fooがnullでもundefineでもないのでテストは成功する
foo.should.exist


.empty

対象の配列の長さが0であることは、lengthプロパティでチェックする

オブジェクトの場合は列挙可能なキーの数を取得する。

# 配列が空であることをテストする

# → 配列が空のため、テストは成功する
[].should.be.empty

# 文字列が空であることをテストする
# → 空文字列のため、テストは成功する
''.should.be.empty

# オブジェクトが空であることをテストする。
# → 空のオブジェクトのため、テストは成功する
{}.should.be.empty


.argument

対象がargumentsオブジェクトか検証する

# argumentsオブジェクトかテストする

# → argumentsオブジェクトなのでテストは成功する
arguments.should.be.arguments


.equal(value)

chainしたオブジェクトが厳密に等しいか(厳密等価演算子:===を使って)を検証する。

# 4であるべきことをテストする。

# → テストは成功する
(4).should.equal 4

# "test"であるべきことをテストする
# → テストは成功する
'test'.should.equal 'test'

# [1, 2, 3]と[1, 2, 3]が等しくないことをテストする
# → テストは成功する
# ※ 参照型の為、オブジェクトとして異なると評価される
[1, 2, 3].should.not.equal [1, 2, 3]

# {foo: 'bar'}と{foo: 'bar'}が等しいことをテストする
# → 参照型の為、オブジェクトの深いレベルまで見ないのでテストは失敗する
{foo: 'bar'}.should.equal {foo: 'bar'}

# {foo: 'bar'}と{foo: 'bar'}が等しくないことをテストする
# → テストは成功する
# ※ 参照型の為、オブジェクトとして異なると評価される
{foo: 'bar'}.should.not.equal {foo: 'bar'}

deepをchainに用いることでオブジェクトの深いレベルで等しいこと検証できる様です。

# {foo: 'bar'}と{foo: 'bar'}が等しいことをテストする

# deepを用いた場合、ターゲットがオブジェクトの深いレベルで等しいことを検証する。
# オブジェクトとしての参照を異なっているが、オブジェクトとして等価の為、テストは成功する
{foo: 'bar'}.should.deep.equal {foo: 'bar'};


.eql(value)

chainしたオブジェクトがvalueと等価か検証する。オブジェクトは実際の内容で比較され、参照による等価比較ではない

# {foo: 'bar'}と{foo: 'bar'}が等しいことをテストする

# → テストは成功する
{foo: 'bar'}.should.eql {foo: 'bar'}

# [1, 2, 3]と[1, 2, 3]が等しいことをテストする
# → テストは成功する
[1, 2, 3].should.eql [1, 2, 3]


.above(value)

対象がvalueよりも大きいことを検証する。

最小の長さを検証するためにlengthと併用される

# 対象10が5より大きいことをテストする

# → 10 > 5 なのでテストは成功する
10.should.be.above 5

# → 同じ10なのでテストは失敗する
10.should.be.above 10

# gtやgreaterThanを使っても書ける
10.should.be.gt 5
10.should.be.greaterThan 5

# fooが2文字より長いことをテストする
# → fooが3文字で2文字より大きいのでテストは成功する
'foo'.should.have.length.above 2

# 配列のサイズが2より大きいことをテストする
# → 配列のサイズは3なので2より大きいのでテストは成功する
[ 1, 2, 3 ].should.have.length.above 2


.least(value)

対象がvalue以上か検証する。

最小の長さを検証するためにlengthと併用される

# 対象が10以上であることをテストする

# → 対象が10以上のためテストは成功する
10.should.be.at.least 10

# gteを使っても書ける
10.should.be.at.gte 10

# 対象が2文字以上であることをテストする
# → 対象"foo"が2文字以上のため、テストは成功す
'foo'.should.have.length.of.at.least 2

# 対象の配列のサイズが3以上であることをテストする
# 対象の配列のサイズが3より以上のためテストは成功する
[ 1, 2, 3 ].should.have.length.of.at.least 3


.below(value)

対象がvalueより小さいことを検証する。

最大の長さを検証するためにlengthと併用される。

# 対象が10以下であることをテストする。

# → 対象が10より小さいのでテストは成功する
5.should.be.below 10

# ltやlessThanも使える
5.should.be.lt 10
5.should.be.lessThan 10

# 文字列"foo"の長さが4より小さいことをテストする
# → 文字列の長さが3なのでテストは成功する
'foo'.should.have.length.below 4

# 配列のサイズが3より小さいことをテストする。
# → 配列のサイズが3なのでテストは成功する
[ 1, 2, 3 ].should.have.length.below 4


.most(value)

対象がvalue以下か検証する。

最大の長さを検証するためにlengthと併用される。

# 5以下であることをテストする

# → 5以下なのでテストは成功する
5.should.be.at.most 5

# lteも使える
5.should.be.at.lte 5

# 文字列"foo"の長さ4以下であることをテストする
# → 文字列の長さが3なのでテストは成功する
'foo'.should.have.length.of.at.most 4

# 配列のサイズが3以下であることをテストする
# → 配列のサイズが3なのでテストは成功する
[ 1, 2, 3 ].should.have.length.of.at.most 3


.within(start, finish)



  • @param{ Number }startlowerbound inclusive


  • @param{ Number }finishupperbound inclusive


  • @param{ String }message_optional_

対象がstartとfinishの範囲内にあるか検証する。

lengthと併用することで、長さの範囲を検証する。

# 7が5〜10の範囲にあるかテストする

# → 7は5〜10の間にあるのでテストは成功する
7.should.be.within 5, 10

# 文字列"foo”が2文字〜4文字の長さを持っていることをテストする
# → 対象の文字列が3文字なので2〜4の間にあるのでテストは成功する
'foo'.should.have.length.within 2, 4

# 配列のサイズが2〜4の要素を持つことをテストする
# → 対象の配列が2〜4のサイズの間にあるのでテストは成功する
[ 1, 2, 3].should.have.length.within 2, 4


.instanceof(constructor)



  • @param{ Constructor }constructor


  • @param{ String }message_optional_

対象がconstructorのインスタンスであることを検証する。

# testerがPersonのインスタンスかテストする

# → 対象がPersonのインスタンスなのでテストは成功する
tester = new Person('tester', 30)
tester.should.be.an.instanceof Person

# instanceOfも使える
tester.should.be.an.instanceOf Person

# 配列[1, 2, 3]がArrayのインスタンスがテストする
# → 配列はArrayのインスタンスなのでテストは成功する
[ 1, 2, 3 ].should.be.instanceof Array


.property(name, [value])

対象がnameプロパティを持つか検証する。

必要に応じてプロパティの値がvalueと厳密に等しいか検証する。

deepフラグを設定したならば、オブジェクトと配列の中の深い参照をドットとブランケット表表記を使用して検証することができる。

# 単純な参照 - objがfooプロパティを持つことをテストする

# → objはfooプロパティを持つのでテストは成功する
obj = {foo: 'bar'}
obj.should.have.property 'foo'

# 単純な参照 - objのfooプロパティが値:barを持つことテストする
# → objのfooプロパティが”bar”と等しいのでテストは成功する
obj = {foo: 'bar'}
obj.should.have.property 'foo', 'bar'

# 深い参照 - green.teaプロパティの値がmatchaであることをテストする
# → deepObjのgreenプロパティが持つオブジェクトがteaプロパティを持ち、その値が"matcha"なのでテストは成功する
deepObj = {
green: { tea: 'matcha' }
, teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
}
deepObj.should.have.deep.property 'green.tea', 'matcha'

# 深い参照 - teasプロパティの値の2つ目の値がmatchaであることをテストする
# → deepObjのteasプロパティが持つ配列の1番目の要素の値が"matcha"なのでテストは成功する
deepObj = {
green: { tea: 'matcha' }
, teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
}
deepObj.should.to.have.deep.property 'teas[1]', 'matcha'

# 深い参照 - teasプロパティの値の3つ目の値(オブジェクト)のteaプロパティがkonachaであることをテストする
# → deepObjのteasプロパティが持つ配列の2番目の要素の値(オブジェクト)のteaプロパティの値が"konacha"なのでテストは成功する
deepObj = {
green: { tea: 'matcha' }
, teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
}
deepObj.should.have.deep.property('teas[2].tea', 'konacha');

また、deep.propertyアサーションでは最初に配列や、ネスとされた配列を使用して検証することができる。

# arrayの要素0が持つ値(配列)の要素1の値がmatchaであることをテストする

# → array[0][1]の値がmatchaなのでテストは成功する
array = [
[ 'chai', 'matcha', 'konacha' ]
, [ { tea: 'chai' }, { tea: 'matcha' }, { tea: 'konacha' } ] ]
array.should.have.deep.property '[0][1]', 'matcha'

# arrayの要素1が持つ値(配列)の要素2の値(オブジェクト)のteaプロパティの値がkonachaであることをテストする
# → array[1][2].teaプロパティの値がkonachaなのでテストは成功する
array = [
[ 'chai', 'matcha', 'konacha' ]
, [ { tea: 'chai' }, { tea: 'matcha' }, { tea: 'konacha' } ] ]
array.should.have.deep.property '[1][2].tea', 'konacha'

さらにpropertyはオリジナルのオブジェクトからプロパティの値へアサーションの対象を変更する。

これはプロパティ上でアサーションの詳細なチェインを許可する。

# objがfooプロパティを持ち、その値がstringがテストする

# → obj.fooプロパティの値がstringなのでテストは成功する
obj = { foo: 'bar'}
obj.should.have.property('foo').that.is.a 'string'

# deepObjがgreenプロパティを持ち、その値がobjectで、{tea: 'matcha'}と等しいことをテストする
# → deepObj.greenプロパティの値がobjectで{tea: matcha}なのでテストは成功する
deepObj = {green: {tea: 'matcha'}}
deepObj.should.have.property('green')
.that.is.an('object')
.that.deep.equals({ tea: 'matcha' })


.ownProperty(name)

対象がnameのプロパティを持つか検証する。

# 文字列"test"がlengthプロパティを持つかテストする

# → 文字列はlengthプロパティを持つのでテストは成功する
'test'.should.have.ownProperty 'length'


.length(value)

対象のlnghthプロパティが期待するvalueを持つことを検証する。

lengthプロパティをチェインして、値の比較を行える。

# 配列のサイズが3であることをテストする

# → 配列の長さが3なのでテストは成功する
[ 1, 2, 3].should.have.length 3

# foobarの文字数が6であることをテストする
# → 文字数が6なのでテストは成功する
'foobar'.should.have.length 6

# fooの文字数が2より大きいことをテストする
# → fooは3文字で2より大きいのでテストは成功する
'foo'.should.have.length.above 2

# 配列のサイズが2よりも大きいことをテストする
# → 配列のサイズは3で2より大きいのでテストは成功する
[ 1, 2, 3 ].should.have.length.above 2

# fooの文字数のサイズが4より小さいことをテストする
# → fooは3文字で4より小さいのでテストは成功する
'foo'.should.have.length.below 4

# 配列のサイズが4より小さいことをテストする
# → 配列のサイズは3で4より小さいのでテストは成功する
[ 1, 2, 3 ].should.have.length.below 4

# fooの文字数が2-4の間にあるかテストする
# → fooは3文字なのでテストは成功する
'foo'.should.have.length.within 2, 4

# 配列のサイズが2-4の間にあることをテストする
# → 配列のサイズは3なのでテストは成功する
[ 1, 2, 3 ].should.have.length.within 2, 4


.match(regexp)



  • @param{ RegExp }RegularExpression


  • @param{ String }message_optional_

対象が正規表現とマッチするか検証する。

# 対象の文字列が正規表現とマッチするかテストする

# → 指定した正規表現とマッチするのでテストは成功する
'foobar'.should.match /^foo/


.string(string)

対象の文字列にstringが含まれているか検証する。

# 対象の文字列"foobar"に"bar"が含まれているかテストする

# → "foobar"に"bar"が含まれているのでテストは成功する
'foobar'.should.have.string 'bar'


.key(key1, [key2], [...])



  • @param{ String... | Array | Object }keys

対象が渡されたキーのいずれか、または全てを含んでいるか検証する。

any、all、contain、またはhaveと組み合わせて使う。

anyと一緒に使用する場合、少なくとも1つのキーが対象のオブジェクトに存在する必要がある。

これはhave または conatain 修飾子が使われるか否かに関わらない。

any、またはallのいずれかはアサーションで使用すべきである。

どちらも使用されない場合はallがデフォルトで使用される。

allとcontainの両方が使われる場合、対象のオブジェクトは渡されたキーの少なくとも全てを持っている必要があるが、記載されていないキーを持っていても良い。

対象のオブジェクトは渡されたキーの数とマッチしている必要があり、渡された全てのキーとキーの数の両方を含まなければいけない。

# 対象のオブジェクトにキーのいずれかを持っているかテストする

# → 対象のオブジェックト{foo: 1, bar: 2}にキー「foo」を持っているのでテストは成功する
{ foo: 1, bar: 2 }.should.have.any.keys 'foo', 'baz'

# 対象のオブジェクトにキーのいずれかを持っているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2}にキー「foo」を持っているのでテストは成功する
{ foo: 1, bar: 2 }.should.have.any.keys 'foo'

# 対象のオブジェクトにキーのいずれかが含まれているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2}にキー「bar」が含まれているのでテストは成功する
{ foo: 1, bar: 2 }.should.contain.any.keys 'bar', 'baz'

# 対象のオブジェクトにキーのいずれかが含まれているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2}にキー「foo」が含まれているのでテストは成功する
{ foo: 1, bar: 2 }.should.contain.any.keys ['foo']

# 対象のオブジェクトにキーのいずれかが含まれているかテストする
# 対象のオブジェックト{foo: 1, bar: 2}にキー「foo」が含まれているのでテストは成功する
{ foo: 1, bar: 2 }.should.contain.any.keys {'foo': 6}

# 対象のオブジェクトに全てのキーを持っているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2}に指定したキー「bar」、「foo」を全て持っているのでテストは成功する
{ foo: 1, bar: 2 }.should.have.all.keys ['bar', 'foo']

# 対象のオブジェクトに全てのキーを持っているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2}に指定したキー「bar」、「foo」を全て持っているのでテストは成功する
{ foo: 1, bar: 2 }.should.have.all.keys {'bar': 6, 'foo': 7}

# 対象のオブジェクトに全てのキーが含まれているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2, baz: 3}は指定したキー「bar」、「foo」を全て含んでいるのでテストは成功する
{ foo: 1, bar: 2, baz: 3 }.should.contain.all.keys ['bar', 'foo']

# 対象のオブジェクトに全てのキーが含まれているかテストする
# → 対象のオブジェックト{foo: 1, bar: 2, baz: 3}は指定したキー「bar」を全て含んでいるのでテストは成功する
{ foo: 1, bar: 2, baz: 3 }.should.contain.all.keys {'bar': 8}


.throw(constructor)



  • @param{ ErrorConstructor }constructor


  • @param{ String | RegExp }expectederror message


  • @param{ String }message_optional_

対象の関数が特定のエラーを投げ、エラーが特定の型(instanceofを使用して決定される)であること、また必要に応じて正規表現(RegExp)、stringを使用してエラーメッセージのが包含されていることを検証する。

err = new ReferenceError('This is a bad function.');

fn = () ->
throw err
# fnがReferenceError型のエラーをスローすることをテストする
# → ReferenceError型のエラーがスローされるのでテストは成功する
fn.should.throw ReferenceError

err = new ReferenceError('This is a bad function.');
fn = () ->
throw err
# fnがError型のエラーをスローすることをテストする
# ReferenceError型のエラーがスローされるのでテストは成功する
fn.should.throw Error

err = new ReferenceError('This is a bad function.');
fn = () ->
throw err
# fnがスローしたエラーに文字列 "bad function"が含まれていることをテストする
# スローされたエラーのエラーメッセージに"bad function"が含まれているのでテストは成功する
fn.should.throw /bad function/

err = new ReferenceError('This is a bad function.');
fn = () ->
throw err
# fnがスローしたエラーの文字列が"good function"でないことをテストする
# → スローされたエラーのエラーメッセージは"good function"でないのでテストは成功する
fn.should.not.throw 'good function'

err = new ReferenceError('This is a bad function.');
fn = () ->
throw err
# fnがスローしたエラーがReferenceError型で、エラーメッセージ "bad function"を含んでいることをテストする
# → スローされたエラーがReferenceError型でエラーメッセージが"bad function"なのでテストは成功する
fn.should.throw ReferenceError, /bad function/

err = new ReferenceError('This is a bad function.');
fn = () ->
throw err
# fnがerrオブジェクトがスローされることをテストする
# → errオブジェクトがスローされるのでテストは成功する
fn.should.throw err

err = new ReferenceError('This is a bad function.');
fn = () ->
throw err
# fnがスローするエラーがRangeErrorオブジェクトでないことをテストする
# スローあれるオブジェクトはReferenceErrorオブジェクトでRangeErrorオブジェクトでないのでテストは成功する
fn.should.not.throw new RangeError('Out of range.')


.respondTo(method)

オブジェクト、またはクラスがメソッドを返すことを検証する。

これ、正直イマイチ良く分からなかった…多分、下記の様な意味合いだとは思うが。

# PersonクラスがgetNameメソッッドを返すことをテストする

# PersonクラスにはgetNameメソッドが定義されているのでテストは成功する
Person.should.respondTo 'getName'

# Personクラスのインスタンス(オブジェクト)がgetNameメソッドを返すことをテストする
# → PersonクラスのオブジェクトががgetNameメソッドを持っているのでテストは成功する
Person person = new Person('test', 30)
person.should.respondTo 'getName'

コンストラクタが静的な関数を返すかチェックするためにitselfフラグを設定する。

# PersonクラスがisPersonメソッド(静的な関数)を返すことをテストする

# PersonクラスにはisPersonメソッド(静的な関数)を定義しているのでテストは成功する
Person.should.itself.respondTo 'isPerson'

# 以下の様にインスタンス関数を指定するとエラーとなる
# Person.should.itself.respondTo 'getName'


.itself

itselfフラグを設定後、respondToアサーションで使われる。

Foo = () ->

Foo.bar = () ->
# Foo関数がbarメソッド(静的な関数)を返すことをテストする
Foo.should.itself.respondTo 'bar'

Foo = () ->
Foo.prototype.baz = () ->
# Foo関数がbazメソッドを返さないことをテストする
Foo.should.itself.not.respondTo 'baz'


.satisfy(method)



  • @param{ Function }matcher


  • @param{ String }message_optional_

対象が与えられた真のテストにパスすることを検証する。

# 1が0より大きいかテストする

# 与えられた関数より、1が0より大きいのでテストは成功する
1.should.satisfy (num) -> return num > 0


.closeTo(expected, delta)

expectedと等しく、その±deltaの範囲内にあることを検証する。

# 1.5が1の+/- 0.5の範囲にあるかテストする

# → 1.5は1に対して+/- 0.5の範囲にあるのでテストは成功する
1.5.should.be.closeTo 1, 0.5


.members(set)

対象がsetのスーパーセット、または、対象とsetが===なメンバーを持つことを検証する。

deepフラグが設定されている場合、setメンバーは深く等しいことを比較する。

# [1, 2, 3]に[3, 2]が含まれていることをテストする

# → [1, 2, 3]に[3, 2]のメンバーが含まれているのでテストは成功する
[1, 2, 3].should.include.members [3, 2]

# [1, 2, 3]に[3, 2, 8]が含まれないことをテストする
# → [1, 2, 3]に[3, 2, 8]全てのメンバーが含まれていない(完全一致していない)のでテストは成功する。
[1, 2, 3].should.not.include.members [3, 2, 8]

# [4, 2]が[2, 4]を持っていることをテストする
# → [4, 2]が[2, 4]を持っているのでテストは成功する
[4, 2].should.have.members [2, 4]

# [5, 2]が[5, 2, 1]を持っていないことをテストする
# → [5 ,2]が[5, 2, 1]全てのメンバーを持っていない(完全に一致していない)のでテストは成功する
[5, 2].should.not.have.members [5, 2, 1]

# [{id: 1}]は[{id: 1}]を含むことをテストする
# → 配列の中に完全に一致するオブジェクトを持つのでテストは成功する
[{ id: 1 }].should.deep.include.members [{ id: 1 }]


.change(function)

functionがオブジェクトのプロパティ変えることを検証する。

obj = { val: 10 }

fn = () -> obj.val += 3
# 関数の呼び出しで引数に指定いたオブジェクトのプロパティが変わることをテストする
# → fnがobj.valを変えるのでテストは成功する
fn.should.change obj, 'val'

obj = { val: 10 }
noChangeFn = () -> return 'foo' + 'bar'
# 関数の呼び出しで引数に指定いたオブジェクトのプロパティが変わらないことをテストする
# → noChangeFnがobj.valを変えないのでテストは成功する
noChangeFn.should.not.change obj, 'val'


.increse(function)

functionがオブジェクトのプロパティを増加させることを検証する。

# functionがobj.valの値を増加させることをテストする

obj = { val: 10 }
fn = () -> obj.val = 15
fn.should.increase obj, 'val'


.decrease(function)

functionがオブジェクトのプロパティを減少させることを検証する。

# functionがobj.valの値を減少させることをテストする

obj = { val: 10 }
fn = () -> obj.val = 5
fn.should.decrease obj, 'val'