私は次のようにしているとしましょう:
var myNumber = 5;
expect(myNumber).toBe(5);
expect(myNumber).toEqual(5);
上記のテストは両方とも合格します。それは数を評価することになるとtoBe()
とtoEqual()
の間に違いはありますか?もしそうなら、私は一方ではなくもう一方を使うべきですか?
プリミティブ型(数値、ブール値、文字列など)では、toBe
とtoEqual
の間に違いはありません。どちらも5
、true
、または"the cake is a lie"
で動作します。
toBe
とtoEqual
の違いを理解するために、3つのオブジェクトを考えてみましょう。
var a = { bar: 'baz' },
b = { foo: a },
c = { foo: a };
厳密な比較(===
)を使用して、いくつかのことは「同じ」です。
> b.foo.bar === c.foo.bar
true
> b.foo.bar === a.bar
true
> c.foo === b.foo
true
しかし、それらが「等しい」とはいえ、いくつかのことは「同じ」ではありません。それらは、メモリ内の異なる場所に存在するオブジェクトを表すからです。
> b === c
false
JasmineのtoBe
マッチャーは厳密な等価比較のためのラッパーにすぎません
expect(a.foo).toBe(b.foo)
と同じものです
expect(a.foo === b.foo).toBe(true)
私のことばをそれだけにしないでください。 toBeのソースコード を参照してください。
しかし、b
とc
は、機能的に同等のオブジェクトを表します。二人とも
{ foo: { bar: 'baz' } }
b
とc
が同じオブジェクトを表していなくても「等しい」と言えるなら、それは素晴らしいことではないでしょうか。
toEqual
を入力します。これは「深い等号」をチェックします(つまり、オブジェクトを再帰的に検索してそれらのキーの値が等しいかどうかを判断します)。次の両方のテストに合格します。
expect(b).not.toBe(c);
expect(b).toEqual(c);
それがいくつかのことを明確にするのに役立ちます願っています。
toBe()
対toEqual()
:toEqual()
は等価性をチェックします。一方、toBe()
は、それらがまったく同じオブジェクトであることを確認します。
値を比較するときはtoBe()
を使用し、オブジェクトを比較するときはtoEqual()
を使用します。
プリミティブ型を比較するとき、toEqual()
とtoBe()
は同じ結果をもたらします。オブジェクトを比較する場合、toBe()
はより厳密な比較であり、メモリ内の正確に同じオブジェクトでない場合、falseを返します。したがって、メモリ内のオブジェクトとまったく同じであることを確認したい場合を除き、オブジェクトの比較にはtoEqual()
を使用します。
詳細については、このリンクを確認してください: http://evanhahn.com/how-do-i-jasmine/
ここで、toBe()
とtoEqual()
の違いを数字で見ると、比較が正しい限り違いはないはずです。 5
は常に5
と同等です。
さまざまな結果を見るためにこれをいじるのに良い場所は here
toBe()
とtoEqual()
を見る簡単な方法は、JavaScriptでそれらが正確に何をするかを理解することです。 Jasmine APIによると、 こちら が見つかりました。
toEqual()は単純なリテラルと変数に対して機能し、オブジェクトに対しても機能するはずです
toBe()は
===
と比較します
基本的に、toEqual()
とtoBe()
は似たJavascript ===
演算子です。ただし、toBe()
は、以下の例でもobjectOne === objectTwo //returns false
でもまったく同じオブジェクトであることを確認しています。ただし、その場合、toEqual()
はtrueを返します。
これで、少なくとも与えられたときの理由を理解できます:
var objectOne = {
propertyOne: str,
propertyTwo: num
}
var objectTwo = {
propertyOne: str,
propertyTwo: num
}
expect(objectOne).toBe(objectTwo); //returns false
これは、 別の、しかし同様の質問に対するこの回答 で述べられているように、===
演算子は実際には両方のオペランドが同じオブジェクトを参照するか、値型の場合は同じ値。
Jasmine githubプロジェクトを引用すると、
expect(x).toEqual(y);
はオブジェクトまたはプリミティブxとyを比較し、それらが等価であればパスします
expect(x).toBe(y);
はオブジェクトまたはプリミティブxとyを比較し、それらが同じオブジェクトであれば渡します
Jasmineのソースコードを見ると、この問題にさらに光が当てられます。
toBe
は非常に単純で、恒等/厳密等価演算子===
を使うだけです。
function(actual, expected) {
return {
pass: actual === expected
};
}
一方、toEqual
は150行近くあり、String
、Number
、Boolean
、Date
、Error
、Element
、RegExp
のような組み込みオブジェクトに対して特別な処理を行います。他のオブジェクトの場合は、プロパティを再帰的に比較します。
これは、等価演算子==
の動作とは大きく異なります。例えば:
var simpleObject = {foo: 'bar'};
expect(simpleObject).toEqual({foo: 'bar'}); //true
simpleObject == {foo: 'bar'}; //false
var castableObject = {toString: function(){return 'bar'}};
expect(castableObject).toEqual('bar'); //false
castableObject == 'bar'; //true
toEqual()
はプリミティブの場合は値を、オブジェクトの場合は内容を比較します。 toBe()
は参照を比較します。
以下のコード/スイートは一目瞭然です。
describe('Understanding toBe vs toEqual', () => {
let obj1, obj2, obj3;
beforeEach(() => {
obj1 = {
a: 1,
b: 'some string',
c: true
};
obj2 = {
a: 1,
b: 'some string',
c: true
};
obj3 = obj1;
});
afterEach(() => {
obj1 = null;
obj2 = null;
obj3 = null;
});
it('Obj1 === Obj2', () => {
expect(obj1).toEqual(obj2);
});
it('Obj1 === Obj3', () => {
expect(obj1).toEqual(obj3);
});
it('Obj1 !=> Obj2', () => {
expect(obj1).not.toBe(obj2);
});
it('Obj1 ==> Obj3', () => {
expect(obj1).toBe(obj3);
});
});
誰かが(注釈付き)例による説明を好むかもしれないと思った:
以下で、私のdeepClone()関数が正しく機能すれば、( 'it()呼び出しで説明されているように)テストは成功するでしょう:
describe('deepClone() array copy', ()=>{
let source:any = {}
let clone:any = source
beforeAll(()=>{
source.a = [1,'string literal',{x:10, obj:{y:4}}]
clone = Utils.deepClone(source) // THE CLONING ACT TO BE TESTED - lets see it it does it right.
})
it('should create a clone which has unique identity, but equal values as the source object',()=>{
expect(source !== clone).toBe(true) // If we have different object instances...
expect(source).not.toBe(clone) // <= synonymous to the above. Will fail if: you remove the '.not', and if: the two being compared are indeed different objects.
expect(source).toEqual(clone) // ...that hold same values, all tests will succeed.
})
})
もちろん、これは私のdeepClone()の完全なテストスイートではありません。配列内のオブジェクトリテラル(およびその中にネストされているもの)にも同一の値があるが同じ値がある場合、ここではテストしていません。