[Finishes #52959947] Warn user about spy conflicts; Refactor spy tests to more reflect responsibilities and removed duplicate tests

This commit is contained in:
Colin O'Byrne and JR Boyens
2013-07-22 16:24:20 -07:00
parent 30aec66ce5
commit 9609aba25f
4 changed files with 109 additions and 205 deletions

View File

@@ -27,6 +27,85 @@ describe("Env", function() {
expect(fakeReporter.jasmineStarted).toHaveBeenCalled();
});
});
it('removes all spies when env is executed', function(done) {
originalFoo = function() {},
testObj = {
foo: originalFoo
},
firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() {
env.spyOn(testObj, 'foo');
}),
secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() {
expect(testObj.foo).toBe(originalFoo);
});
env.describe('test suite', function() {
env.it('spec 0', firstSpec);
env.it('spec 1', secondSpec);
});
var assertions = function() {
expect(firstSpec).toHaveBeenCalled();
expect(secondSpec).toHaveBeenCalled();
done();
};
env.addReporter({ jasmineDone: assertions });
env.execute();
});
describe("#spyOn", function() {
it("checks for the existance of the object", function() {
expect(function() {
env.spyOn(void 0, 'pants');
}).toThrowError(/could not find an object/);
});
it("checks for the existance of the method", function() {
var subject = {};
expect(function() {
env.spyOn(subject, 'pants');
}).toThrowError(/method does not exist/);
});
it("checks if it has already been spied upon", function() {
var subject = { spiedFunc: function() {} };
env.spyOn(subject, 'spiedFunc');
expect(function() {
env.spyOn(subject, 'spiedFunc');
}).toThrowError(/has already been spied upon/);
});
it("overrides the method on the object and returns the spy", function() {
var originalFunctionWasCalled = false;
var subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
originalFunc = subject.spiedFunc;
var spy = env.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
expect(subject.spiedFunc.calls.any()).toEqual(false);
expect(subject.spiedFunc.calls.count()).toEqual(0);
subject.spiedFunc('foo');
expect(subject.spiedFunc.calls.any()).toEqual(true);
expect(subject.spiedFunc.calls.count()).toEqual(1);
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['foo']);
expect(subject.spiedFunc.calls.mostRecent().object).toEqual(subject);
expect(originalFunctionWasCalled).toEqual(false);
subject.spiedFunc('bar');
expect(subject.spiedFunc.calls.count()).toEqual(2);
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']);
});
});
describe("#catchException", function() {
it("returns true if the exception is a pending spec exception", function() {

View File

@@ -1,210 +1,31 @@
describe('Spies', function () {
var env;
beforeEach(function() {
env = new j$.Env();
});
describe("createSpy", function() {
var TestClass;
it('should replace the specified function with a spy object', function() {
var originalFunctionWasCalled = false;
var TestClass = {
someFunction: function() {
originalFunctionWasCalled = true;
}
};
env.spyOn(TestClass, 'someFunction');
beforeEach(function() {
TestClass = function() {};
TestClass.prototype.someFunction = function() {};
TestClass.prototype.someFunction.bob = "test";
});
it("preserves the properties of the spied function", function() {
var spy = j$.createSpy(TestClass.prototype, TestClass.prototype.someFunction);
expect(TestClass.someFunction.calls.any()).toEqual(false);
expect(TestClass.someFunction.calls.count()).toEqual(0);
TestClass.someFunction('foo');
expect(TestClass.someFunction.calls.any()).toEqual(true);
expect(TestClass.someFunction.calls.count()).toEqual(1);
expect(TestClass.someFunction.calls.mostRecent().args).toEqual(['foo']);
expect(TestClass.someFunction.calls.mostRecent().object).toEqual(TestClass);
expect(originalFunctionWasCalled).toEqual(false);
TestClass.someFunction('bar');
expect(TestClass.someFunction.calls.count()).toEqual(2);
expect(TestClass.someFunction.calls.mostRecent().args).toEqual(['bar']);
});
it('should allow you to view args for a particular call', function() {
var originalFunctionWasCalled = false;
var TestClass = {
someFunction: function() {
originalFunctionWasCalled = true;
}
};
env.spyOn(TestClass, 'someFunction');
TestClass.someFunction('foo');
TestClass.someFunction('bar');
expect(TestClass.someFunction.calls.first().args).toEqual(['foo']);
expect(TestClass.someFunction.calls.mostRecent().args).toEqual(['bar']);
});
it('should be possible to call through to the original method, or return a specific result', function() {
var originalFunctionWasCalled = false;
var passedArgs;
var passedObj;
var TestClass = {
someFunction: function() {
originalFunctionWasCalled = true;
passedArgs = Array.prototype.slice.call(arguments, 0);
passedObj = this;
return "return value from original function";
}
};
env.spyOn(TestClass, 'someFunction').and.callThrough();
var result = TestClass.someFunction('arg1', 'arg2');
expect(result).toEqual("return value from original function");
expect(originalFunctionWasCalled).toEqual(true);
expect(passedArgs).toEqual(['arg1', 'arg2']);
expect(passedObj).toEqual(TestClass);
expect(TestClass.someFunction.calls.any()).toEqual(true);
});
it('should be possible to return a specific value', function() {
var originalFunctionWasCalled = false;
var TestClass = {
someFunction: function() {
originalFunctionWasCalled = true;
return "return value from original function";
}
};
env.spyOn(TestClass, 'someFunction').and.callReturn("some value");
originalFunctionWasCalled = false;
var result = TestClass.someFunction('arg1', 'arg2');
expect(result).toEqual("some value");
expect(originalFunctionWasCalled).toEqual(false);
});
it('should be possible to throw a specific error', function() {
var originalFunctionWasCalled = false;
var TestClass = {
someFunction: function() {
originalFunctionWasCalled = true;
return "return value from original function";
}
};
env.spyOn(TestClass, 'someFunction').and.callThrow(new Error('fake error'));
var exception;
try {
TestClass.someFunction('arg1', 'arg2');
} catch (e) {
exception = e;
}
expect(exception.message).toEqual('fake error');
expect(originalFunctionWasCalled).toEqual(false);
});
it('should be possible to call a specified function', function() {
var originalFunctionWasCalled = false;
var fakeFunctionWasCalled = false;
var passedArgs;
var passedObj;
var TestClass = {
someFunction: function() {
originalFunctionWasCalled = true;
return "return value from original function";
}
};
env.spyOn(TestClass, 'someFunction').and.callFake(function() {
fakeFunctionWasCalled = true;
passedArgs = Array.prototype.slice.call(arguments, 0);
passedObj = this;
return "return value from fake function";
expect(spy.bob).toEqual("test");
});
var result = TestClass.someFunction('arg1', 'arg2');
expect(result).toEqual("return value from fake function");
expect(originalFunctionWasCalled).toEqual(false);
expect(fakeFunctionWasCalled).toEqual(true);
expect(passedArgs).toEqual(['arg1', 'arg2']);
expect(passedObj).toEqual(TestClass);
expect(TestClass.someFunction.calls.any()).toEqual(true);
});
it('removes all spies when env is executed', function(done) {
var env = new j$.Env(),
originalFoo = function() {},
testObj = {
foo: originalFoo
},
firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() {
env.spyOn(testObj, 'foo');
}),
secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() {
expect(testObj.foo).toBe(originalFoo);
});
env.describe('test suite', function() {
env.it('spec 0', firstSpec);
env.it('spec 1', secondSpec);
it("warns the user that we indend to overwrite an existing property", function() {
expect(function() {
j$.createSpy(TestClass.prototype, TestClass.prototype.someFunction);
}).toThrowError("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
});
var assertions = function() {
expect(firstSpec).toHaveBeenCalled();
expect(secondSpec).toHaveBeenCalled();
done();
};
it("adds a spyStrategy and callTracker to the spy", function() {
var spy = j$.createSpy(TestClass.prototype, TestClass.prototype.someFunction);
env.addReporter({ jasmineDone: assertions });
env.execute();
});
it('throws an exception when some method is spied on twice', function() {
var TestClass = { someFunction: function() {
} };
env.spyOn(TestClass, 'someFunction');
var exception;
try {
env.spyOn(TestClass, 'someFunction');
} catch (e) {
exception = e;
}
expect(exception).toBeDefined();
});
it('to spy on an undefined method throws exception', function() {
var TestClass = {
someFunction : function() {
}
};
function efunc() {
env.spyOn(TestClass, 'someOtherFunction');
}
expect(function() {
efunc();
}).toThrow('someOtherFunction() method does not exist');
});
it('should be able to reset a spy', function() {
var TestClass = { someFunction: function() {} };
env.spyOn(TestClass, 'someFunction');
expect(TestClass.someFunction).not.toHaveBeenCalled();
TestClass.someFunction();
expect(TestClass.someFunction).toHaveBeenCalled();
TestClass.someFunction.calls.reset();
expect(TestClass.someFunction).not.toHaveBeenCalled();
expect(TestClass.someFunction.calls.count()).toEqual(0);
});
it("preserves the properties of the spied function", function() {
var TestClass = function() {};
TestClass.prototype.someFunction = function() {};
TestClass.prototype.someFunction.bob = "test";
var spy = env.spyOn(TestClass.prototype, 'someFunction');
expect(spy.bob).toEqual("test");
expect(spy.and).toEqual(jasmine.any(j$.SpyStrategy);
expect(spy.calls).toEqual(jasmine.any(j$.CallTracker);
});
});
describe("createSpyObj", function() {

View File

@@ -211,16 +211,16 @@ getJasmineRequireObj().Env = function(j$) {
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw "spyOn could not find an object to spy upon for " + methodName + "()";
throw new Error("spyOn could not find an object to spy upon for " + methodName + "()");
}
if (j$.util.isUndefined(obj[methodName])) {
throw methodName + '() method does not exist';
throw new Error(methodName + '() method does not exist');
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw methodName + ' has already been spied upon';
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);

View File

@@ -65,13 +65,17 @@ getJasmineRequireObj().base = function(j$) {
return spyStrategy.exec.apply(this, arguments);
};
spy.and = spyStrategy;
spy.calls = callTracker;
for (var prop in originalFn) {
if (prop === 'and' || prop === 'calls') {
throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
}
for (prop in originalFn) {
spy[prop] = originalFn[prop];
}
spy.and = spyStrategy;
spy.calls = callTracker;
return spy;
};