Get Line number or trace of a function call

JavaScript and client side scripting.

Moderator: General Moderators

Post Reply
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Get Line number or trace of a function call

Post by Chris Corbyn »

I'm not fussed if this is browsers specific for now, but without throwing exceptions to do it, is it possible to get the line number at which a method was called?

I'm trying my hand at writing a *light* Unit Testing toolkit for JS which will allow JSMock to be used (or a re-write of it) since I don't particularly like the interface or test suite of JSUnit. JSUnit doesn't provide line numbers but I figured it must be possible.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Hmm.. I just went with try/catch exceptions in the end. I've only tested it on FF thus far so I imagine I'll hit some roadblocks but:

Code: Select all

/**
 * A basic exception object
 * @package JSTester
 * @author Chris Corbyn
 * @constructor
 */
function JSTesterException(message)
{
	/**
	 * We give exceptions a name so we know what they relate to
	 * @type String name
	 */
	this.name = 'JSTesterException';
	/**
	 * The message for this exception
	 * @type String comment
	 */
	this.comment = message;
	
	/**
	 * What do if we ask for a string
	 * @return <string>
	 */
	this.toString = function()
	{
		return this.comment;
	}
}

JSTesterException.prototype = new Error();
The fact it inherits from type Error() gives it fileName, lineNumber, stack etc...
dewindj
Forum Newbie
Posts: 4
Joined: Sun Sep 24, 2006 7:29 pm

Post by dewindj »

I'd be interested in seeing JSMock's success within other unit testing frameworks other than JSUnit. I wrote JSMock within the JSUnit framework, not necessarily for the JSUnit framework.

Additonally, I'm glad to see someone is practicing TDD on a language that many consider to be, 'something you don't unit test'. Which is odd considering it is developed on by thousands of developers, and used by millions of clients.

Good luck!
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Hello :)

Good work on JSMock. I have to say, I'm not a fan of the JSUnit interface or the requirement to use the test runner which is partly why I'm writing my own. I don't any big plans to release it since the code probably doesn't follow some standards in terms of the API testing frameworks should provide. I have some pass() and fail() methods. I can make assertions. I can detect exceptions and pinpoint line numbers and I now have some basic mock functionality working. I haven't looked at the code behind JSMock too much but I'll try to work my API in a fashion that allows it.

The difference with what I'm writing an JSUnit is that my test cases are individually encapsulated into classes like SimpleTest in PHP. The reporter is a separate component just like SimpleTest too. You just run the test right from the file the test is in... heck, it even looks as simplistic as SimpleTest. I should probably seek some guidance on "standards" for the API around which to base assertions before I go too far with it in order to allow other components from other toolkits (such as JSMock) to be used.

I actually started writing the Mock objects part of the framework from scratch. It's not brilliant (at a backend level, maybe?) but I now have Full Mocks (with additional mock methods) and Partial Mocks with the usual assertions and stub features. It's not quite JSMock though :P I tried to take a KISS approach (as I do with everything) and simply "inject" methods etc into a skeleton mock object which contains the features needed such as setReturnValue(), setReturnValueAt(), assertCalledNever() etc. One flaw in my design is that you need to create an instance of the mock interface before it can be mocked (because I loop over all the methods in it). I could probably works this better with hindsight and read what's on the constructor instead... I'm only a few hours in though.

For example (this test has no real meaning, it's the remnants of something I was playing with):

Code: Select all

this.testOfNothing = function()
	{
		//Note the need to make "new myObj()"!!
		var mockFactory = new Mock(new myObj(), this);
		mock = mockFactory.generate(new Array('zipButton')); //Added mock method not in real interface
		mock.zipButton();
		mock.assertCalledOnce('zipButton');
		mock.setReturnValueAt('somethingFoo', 42, 1);
		mock.setReturnValueAt('somethingFoo', 10, 2);
		this.assertEqual(42, mock.somethingFoo());
		this.assertEqual(10, mock.somethingFoo());
		mock.assertCalledAtLeastOnce('somethingFoo');
		mock.testing();
		mock.assertCallCount('testing', 1);
	}
Other bits and pieces I'd like in place are:

* window event capturing (e.g. if a class throws an alert() don't actually do alert() but have some fake window object catch that it was called)
* Mock events to attach to DOM nodes and then execute (i.e. a Mock mouseover event which tiggers actions like a real mouseover)
* More "correct" assertion API for scalability/portability
* As much cross browser support as possible

I'm quite a fan of keeping things as non-complex/readable as possible.

If I got it up to a certain usable stage would you want to take a look at the code from SVN and see what I would need to change to get JSMock support in it? :)
dewindj
Forum Newbie
Posts: 4
Joined: Sun Sep 24, 2006 7:29 pm

Post by dewindj »


Other bits and pieces I'd like in place are:

* window event capturing (e.g. if a class throws an alert() don't actually do alert() but have some fake window object catch that it was called)
* Mock events to attach to DOM nodes and then execute (i.e. a Mock mouseover event which tiggers actions like a real mouseover)
* More "correct" assertion API for scalability/portability
* As much cross browser support as possible

I'm quite a fan of keeping things as non-complex/readable as possible.

If I got it up to a certain usable stage would you want to take a look at the code from SVN and see what I would need to change to get JSMock support in it? :)
1. One way to enable this, is to inject a mock into a variable that represents a window. For instance, instead of using the window object directly to call alerts, have a variable that holds reference to the window object. That way, it is easy to inject a mock that you can assert expectations of an alert on.

2. Can't you assign a mock call to a mouseover callback? E.g. node.onmouseover = mock.onMouseDoNeatStuff

As for JSMock support, I'm not entirely sure what is required of it to have JSMock work in it. All JSMock does when expectations aren't met is throw an error that makes your tests break. But, yeah, I have no problem helping you through any road blocks that make JSMock incompatible with the current unit testing framework that you are making.

By the way, I pushed out a 1.1 release of JSMock last night that allows mocks to add methods to themselves, which should make the library a lot more flexible in testing.
dewindj
Forum Newbie
Posts: 4
Joined: Sun Sep 24, 2006 7:29 pm

Post by dewindj »

Oh, and since the context of 'this' in javascript is so terrible, JSmock does require some massaging when passing around functions on a mock.

For instance, assigning a mock callback for onmouseover of window could be done like this:

Code: Select all

mock = control.createMock();
mock.addMockMethod("onMouseover");

//Doesn't work
window.onmouseover = mock.onMouseover
//Works
window.onmouseover = function() { mock.onMouseover() }
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

dewindj wrote:Oh, and since the context of 'this' in javascript is so terrible, JSmock does require some massaging when passing around functions on a mock.

For instance, assigning a mock callback for onmouseover of window could be done like this:

Code: Select all

mock = control.createMock();
mock.addMockMethod("onMouseover");

//Doesn't work
window.onmouseover = mock.onMouseover
//Works
window.onmouseover = function() { mock.onMouseover() }
JSMock will certainly work with my testing framework then. If it throws an exception it will be picked up. If the exception contains a property "__testfail = true" it will not *show* as an exception, but rather it will show as a failure as if it was an expected failure. It's easy to inject such a property into an error object ;)

My idea was to trigger the mouseover event with the required properties to make it a little more "real" kinda like (this is entirely thoughts in my head). It might even be possible to completely mock a native event object.

Code: Select all

someNode.onmouseover = someMock.someMethod;

var mockMouseover = new MockEvent('MOUSEOVER');

mockMouseover.setXPosition(100);
mockMouseover.setYPosition(200);

mockMouseover.attachTo(someNode);

mockMouseover.trigger(); //Triggers the mouseover even on someNode as if the cursor was at coordinates (100,200)
Triggering the actuall callback is easy:

Code: Select all

this.trigger  = function()
{
    this.thingImAttachedTo.onmouseover(this);
}
Maybe I'll realise that I don't need this after all. It will be extremely interesting to get this to a point where it can be conmpared against other frameworks and tested with JSMock. Like I say, this is mostly for my own use at the moment (*cough* I'll be using it in a *cough* agile development oriented PHP/Ajax/JS application framework).
dewindj
Forum Newbie
Posts: 4
Joined: Sun Sep 24, 2006 7:29 pm

Post by dewindj »

It appears to me at least, that you are trying to write functional acceptance tests that do more than just test a unit of behavior. I'm assuming you want to test that the location of nodes and assert their location by triggering fake event handlers via mouse clicks? Testing the behavior of the application as a whole is definitely trickier than unit testing, and have event helpers that do 'real' mouse clicks would be neat.

Have you ever looked into WATIR, or Selenium?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

dewindj wrote:It appears to me at least, that you are trying to write functional acceptance tests that do more than just test a unit of behavior. I'm assuming you want to test that the location of nodes and assert their location by triggering fake event handlers via mouse clicks? Testing the behavior of the application as a whole is definitely trickier than unit testing, and have event helpers that do 'real' mouse clicks would be neat.
Sorry let me rephrase "mocked event" to "simulated event".

No user interaction would be required for the tests to work; the events would behave as actors in the test and simulate the behaviour of a user. Events are a key part of the language so I do believe it would be useful to emulate such activity within a test case. Again, these are just initial thoughts. I can open the Trac wiki up to discussion perhaps :)

I agree that testing the behaviour when I real user is playing with a DHTML menu for example would be beyond the realms of unit testing and more into integration/acceptance testing. I'm concious of avoiding crossing that boundary here. All I plan on doing is creating some basic way of simulating an event without actually having the user make it happen.
Have you ever looked into WATIR, or Selenium?
I haven't no. But I will do. I'm aware of them :)
Post Reply