by date
Mock-objects for TorqueScript
Mock-objects for TorqueScript
| Name: | BlueRaja | |
|---|---|---|
| Date Posted: | Jul 30, 2008 | |
| Rating: | 4.0 out of 5 | |
| Public: | YES | |
| Comments: | YES | |
| RSS Feed: | or Subscribe with . | |
| Profile Page: | View profile page for BlueRaja |
Blog post
Completed for this release of TUnit: a mocking framework for TorqueScript!
What is a mocking framework?
When running unit-tests, one typically wants to test just that - a unit (or single class). However, if your class relies on other classes, bugs in those other classes could cause tests for your class to fail. This is where mock-objects come into play - mock-objects allow you to, in essence, create "fake instances" for each of the dependencies of your class, meaning your class can be tested in complete isolation from all other classes. You can define expectations of and give custom behaviours to these objects, which your test-class then uses as though they were the actual objects it expects them to be. Now when a unit-test fails, you can be sure that it's because of a bug in the class you're actually testing!
Mock-objects can also be used if your class relies on another class that has not been written yet, and are helpful for a variety of other reasons.
Using TUnit mocks
To create a mock, use Mock::createMock(ClassName), replacing ClassName with the name of the class you want to mock.
Expectations take the form
expectationModifiers consist of the following:
(Expectation modifiers can be chained)
Finally, when all expectations are set up, call
Then run the test methods, and all expectations with be verified automatically.
For example, to assert that %target.myMethod(%var); will call %var.add(5) at least twice, you might do the following:
More examples can be found in MockTests.cs
Downloading TUnit mocks
The mocks package is included with the latest release of TUnit, a link to which can be found in my previous post on unit-tests.
FAQ.
Q. Where can I learn more about what mock-objects are and how to use them?
A. Try googling.
Q. Is there a way to specify the order I want methods called in, or to do different things on different calls of the same method (with the same parameters)?
A. Yes and no; no, in that neither of these things are directly supported, the way they are in some other mock-packages. Yes, in that these can both be easily accomplished using a callback (calls()) and some simple logic. There are no plans to add either of these features in the future, as I almost never have to use them, but if I get enough requests I may reconsider.
What is a mocking framework?
When running unit-tests, one typically wants to test just that - a unit (or single class). However, if your class relies on other classes, bugs in those other classes could cause tests for your class to fail. This is where mock-objects come into play - mock-objects allow you to, in essence, create "fake instances" for each of the dependencies of your class, meaning your class can be tested in complete isolation from all other classes. You can define expectations of and give custom behaviours to these objects, which your test-class then uses as though they were the actual objects it expects them to be. Now when a unit-test fails, you can be sure that it's because of a bug in the class you're actually testing!
Mock-objects can also be used if your class relies on another class that has not been written yet, and are helpful for a variety of other reasons.
Using TUnit mocks
To create a mock, use Mock::createMock(ClassName), replacing ClassName with the name of the class you want to mock.
%myMockedObj = Mock::createMock(SimSet);
Expectations take the form
%mockedVariable.methodToExpect(parameters).expectationModifiers
//Call-count
callOnce(); //This method should be called exactly once
callNone(); //This method should never be called
callAny(); //This method can be called any number of times
callExactly(%times); //This method should be called exactly %times times.
callAtLeast(%times); //Call at least %times times
callAtMost(%times); //Call at most %times times
//Actions
calls(%functionName); //Calls the function with the given name. No parentheses are needed.
// The value returned by the function is also returned when the
// mocked-method is called.
returns(%value); //The method returns the value %value. returns() is ignored if
// calls() is specified
callOriginalMethod(); //Calls the original implementation of the method that is being
// mocked.
//Parameter-matching
ignoreArguments(); //Matches the expectation on any call to the method, regardless
// of parameters
ignore(); //Same as ignoreArguments().callAny()
Finally, when all expectations are set up, call
Mock::replayAll();
For example, to assert that %target.myMethod(%var); will call %var.add(5) at least twice, you might do the following:
function MyTests::myMethodTest()
{
//Setup %target here or in setup()...
%var = Mock::createMock(SimSet);
%var.add(5).callAtLeast(2);
Mock::replayAll();
%target.myMethod(%var);
}
More examples can be found in MockTests.cs
Downloading TUnit mocks
The mocks package is included with the latest release of TUnit, a link to which can be found in my previous post on unit-tests.
FAQ.
Q. Where can I learn more about what mock-objects are and how to use them?
A. Try googling.
Q. Is there a way to specify the order I want methods called in, or to do different things on different calls of the same method (with the same parameters)?
A. Yes and no; no, in that neither of these things are directly supported, the way they are in some other mock-packages. Yes, in that these can both be easily accomplished using a callback (calls()) and some simple logic. There are no plans to add either of these features in the future, as I almost never have to use them, but if I get enough requests I may reconsider.
Recent Blog Posts
| List: | 07/30/08 - Mock-objects for TorqueScript 07/20/08 - Unit Tests for Torque Script |
|---|
Submit your own resources!| Novack (Aug 01, 2008 at 03:12 GMT) |
| Joe Calabrese (Aug 06, 2008 at 12:42 GMT) |
I'm trying to figure out the best way to implement this in a real game, using realistic tests.
From what I know about unit testing and mocking, a common approach is to isolate the tests to just the specific, desired class through Dependency Injection. The injected dependencies are mock objects. If one of the dependencies is the View object (using a Model-View-Presenter type of Design Pattern), then all of the tests can be run without any UI actually occurring.
I don't quite see how this can be effectively implemented in TorqueScript. Do you have any examples of a real game using TUnit and the mock objects? That would help a lot.
| BlueRaja (Aug 07, 2008 at 18:49 GMT) Resource Rating: 5 |
As for your other point: yes, separating the view from the logic would definitely be for the best, even when not testing. However, I realize that's probably not always possible, for instance when using engine objects that have their logic and view tightly integrated.
The best option would be to create a partial-mock by mocking some methods and not others. To do this, I would have to create something along the lines of a callOriginalMethod expectation - perhaps I'll do that when I get time.
The other option would be to use the fact that the this pointer can be passed as an argument in TorqueScript and mock the target-object itself! That is, rather than doing this:
%target.myMethod(%parameter);
MyClass::myMethod(%target, %parameter);
If you use this second approach, just make sure to test the "private" methods as well.
PS. Rhino Mocks is my favorite mocking framework, so thank you for the compliment. I also read the Ayende Rahien blog regularly, and love it!
[edit]Eh, I added a callOriginalMethod expectation.
Edited on Aug 08, 2008 03:14 GMT
You must be a member and be logged in to either append comments or rate this resource.


4.0 out of 5


