Page 1 of 1

JavaScript Destructor?

Posted: Sun Sep 24, 2006 12:35 pm
by Chris Corbyn
Is there a destructor implementation in JavaScript?

I'm writing a Mock object factory and need it to inject some sort of destructor method to work nicely.

At the moment you can provide expectOnce() type assertions on the Mock but the problem is that they will try to run at the time you call them rather than later so you need to call expectOnce() *after* any operations were done on the mock. If I could have it just set something up and then check once the object destructs it would allow the call to be made anywhere. Unless there's perhaps a better way than my current approach?

Here's how it works at the moment:

Code: Select all

function interfaceToMock()
{
    this.someMethod = function() {}
    this.anotherMethod = function() {}
}

Code: Select all

function myTestCase()
{
    this.testMockRunsACertainMethod = function()
    {
        var mockfactory = new Mock(new interfaceToMock());
        var myMock = mockfactory.generate('myMockName');
        myMock.setReturnValue('someMethod', 42);
        this.assertEqual(42, myMock.someMethod());
        myMock.expectOnce('someMethod'); //Works because we ran it earlier
    }
}

myTestCase.prototype = new UnitTestCase();
myTestCase.run(new DefaultRunner());
and the factory code:

Code: Select all

function Mock(theClass)
{
	this.generate = function(name, testcase)
	{
		var mockObj = new Object();
		mockObj._retvals = new Array();
		mockObj._calls = new Array();
		mockObj._testcase = testcase;
		
		mockObj.setReturnValue = function(f, v)
		{
			mockObj._retvals[f] = v;
		}
		
		mockObj.expectOnce = function(f)
		{
			if (mockObj._calls[f] != 1)
			{
				throw new JSTesterException('Mock expectOnce assertion failed with count ' + mockObj._calls[f]);
			}
			else
			{
				mockObj._testcase.pass('Mock expectOnce passed, OK');
			}
		}
		
		for (var _x in theClass)
		{
			if (typeof theClass[_x] == 'function')
			{
				mockObj._retvals[_x] = null;
				mockObj._calls[_x] = 0;
				
				mockObj[_x] = function()
				{
					if (Mock.isGenerated(name, _x))
					{
						mockObj._calls[_x]++;
						return mockObj._retvals[_x];
					}
					else
					{
						Mock.setGenerated(name, _x);
					}
				}
			}
		}
		
		return mockObj;
	}
}

Mock._completelyGenerated = new Array();
Mock.setGenerated = function(n, f)
{
	if (typeof this._completelyGenerated[n] == 'undefined')
	{
		this._completelyGenerated[n] = new Array();
	}
	this._completelyGenerated[n][f] = true;
}
Mock.isGenerated = function(n, f)
{
	if (typeof this._completelyGenerated[n] == 'undefined') return false;
	else
	{
		if (typeof this._completelyGenerated[n][f] != 'undefined') return true;
	}
}

Re: JavaScript Destructor?

Posted: Sun Sep 24, 2006 1:09 pm
by feyd
d11wtq wrote:Is there a destructor implementation in JavaScript?
Unless something's changed somewhat recently, no.

Posted: Sun Sep 24, 2006 1:22 pm
by Chris Corbyn
Do you think it's a bad thing if the expects calls need to be made after any operations were run on the mock?

Posted: Sun Sep 24, 2006 1:32 pm
by Weirdan
Do you think it's a bad thing if the expects calls need to be made after any operations were run on the mock?
I think it's somewhat misleading. Though you may name them like 'assertCallCount'...

Posted: Sun Sep 24, 2006 1:43 pm
by Chris Corbyn
Weirdan wrote:
Do you think it's a bad thing if the expects calls need to be made after any operations were run on the mock?
I think it's somewhat misleading. Though you may name them like 'assertCallCount'...
Yeah I might do that thanks.

assertCallCount()
assertCalledOnce()
assertCalledAtLeastOnce()
assertCalledNever()

I'll post back if I run into any other issues :)

EDIT | I'd actually like to come up with a clean way of generating mocked events too like:

Code: Select all

    this.testActionRunsOnMouseover = function()
    {
        var myMock = mockFactory.generate('MockMyObj');

        var someDiv = document.createElement('div');

        someDiv.onmouseover = myMock.doSomething;
        
        var mockMouseover = new MockEvent('MOUSEOVER');
        mockMouseover.setX(200);
        mockMouseover.setY(100);
        mockMouseover.attachTo(someDiv);
        mockMouseover.tigger();

        myMock.assertCalledOnce('doSomething');
    }