unit testing?

futnuh

15-08-2007 02:09:50

I'm curious if anyone is writing unit tests to develop their python-ogre projects? I use unit tests on the core parts of my engine (scheduling, finite-state machines, networking, etc.) but not the actual Ogre-related stuff. I'd be curious to hear from anyone who is ...

Game_Ender

15-08-2007 04:21:47

I have been thinking about Unit Testing Ogre related projects for a while now. Right now the best option I could think of would be a null renderer/window system which would still enable scene managers and everything to function to properly but not create any windows or render anything. This would allow you test classes that manipulate the scene graph and such.

I think people have gotten close to having a complete one, but I haven't seen anything released. It would be great if something like this was included in Ogre.

ethankennerly

27-10-2007 03:58:23

Hm. I too need unit testing.

Sorry, this is a newbie issue. The "go()" method starts an application and relinquishes control of the frames, so that additional commands are not executed until "go()" is terminated. So, how can start the renderer in a fashion that allows a command to be run in between frameStarted methods? I am using doctest, in which I'd like to do something like set an object position at the start, run some code, and test the object's new position, all within Ogre. Have you seen this kind of thing done before?

-- Ethan

andy

27-10-2007 05:48:33

You can always use a loop that calls renderOneFrame()..

Have a look at demos/ogre/Demo_Spinner.py for one implementation..

Of course the other way (IMHO the prefered way :wink: ) is to use a FrameListener and get called on every frame (either before or after the frame).. There are many demos that use this technique (Demo_SkyBox/CameraTracking/Lighting/SkyDome...)

Regards
Andy

Game_Ender

27-10-2007 22:41:41

Actually, for a practical application the preferred way is to not use FrameListeners for anything not linked to rendering. That way you can decouple the update rate of everything else in your game from Ogre. Remember the demos show you how to use a single feature of Ogre, not the best way structure an Ogre application.

See the "PracticalApplication" on Ogre's wiki for more information.

scriptkid

29-10-2007 13:07:38

Also note that you don't always need a 'view'. Assuming that you say "unit test" as in "automatic test", you can do alot without an actual renderer. My unit testing module only sets up Ogre until a valid SceneManager. With that ready, you can do lot's of Ogre stuff already without an actual render.

However i do think that Ogre needs to render at least once in order to calculate bounding area's and such. But it's been a while since i ran into such issues, so i might be wrong.

ethankennerly

14-11-2007 02:07:45

Thanks for the leads. I modified the Demo_Spinner.py to create a unit test. Here is a hacked unit test demo. If you have advice for improvements I'd like to hear it.

To experiment more efficiently in Python-Ogre, I find myself looking for two more things:

1. PyCrust is a great shell for examining variables during run time, is quite a powerful IDE-aide when coupled with PythonCard. Is there any interpreter that conveniently works with Python-Ogre to inspect member values during run-time?

2. Also, I wanted to automatically test some user input and the expected response. Is there a simple way to spoof keyboard/mouse input? I have abstracted user interface from the simulation and unit tested the simulation, but I was curious about testing the user interface, automatically, too.


'''
Demonstration of a unit test in Python-Ogre, by modifying the essential parts
of the Spinning Ninja in Python-Ogre Demo_Spinner.py.
Use this as a template for creating your own unit tests that
do not require rendering or a window, but do require Ogre scene manager
and frames.
'''
import sys
import time

import ogre.renderer.OGRE as ogre
import ogre.io.OIS as OIS

_debug_unit = False

def _choose_render_engine(app):

# for now this forces D3D
rend_list = app.root.getAvailableRenderers()
app.root.setRenderSystem(rend_list[-1])

def _load_resources(app, resource_path):
config = ogre.ConfigFile()
config.load(resource_path)
section_iter = config.getSectionIterator()
while section_iter.hasMoreElements():
section_name = section_iter.peekNextKey()
settings = section_iter.getNext()
for item in settings:
app.rgm.addResourceLocation(item.value, item.key, section_name)

def unit_test_initialise( app, plugins_path, resource_path ):
self = app
self.plugins_path = plugins_path
self.resource_path = resource_path
# gotta have a Root object :)
self.root = ogre.Root(plugins_path)
if _debug_unit: print "--- Root created"
_choose_render_engine(self)
self.root.initialise(False)
if _debug_unit: print "--- initialise"

self.sceneManager = self.root.createSceneManager(ogre.ST_GENERIC)
if _debug_unit: print "--- CreateSceneManager"

self.sceneManager.setAmbientLight(ogre.ColourValue(1, 1, 1))

# keep track of the resource manager

self.rgm = ogre.ResourceGroupManager.getSingleton()
_load_resources(self, self.resource_path)
if _debug_unit: print "--- _load_resources"

# Do not initialise the resources.



class MyApp(object):
'''
Unit test that ninja spins.
>>> self = MyApp()
>>> self.ninja.update( frame_interval = 0 )
>>> self.ninja.start_spinning(-1)
>>> self.ninja.update( frame_interval = 1 )

The radians should be PI - 1, or 2.14...
>>> print round(self.ninja.node.orientation.getYaw().valueRadians(), 2)
2.14
>>> self.ninja.stop_spinning()
>>> self.ninja.update( frame_interval = 1 )
>>> print round(self.ninja.node.orientation.getYaw().valueRadians(), 2)
2.14
>>> self.ninja.start_spinning(1)
>>> self.ninja.update( frame_interval = 1 )

>>> print round(self.ninja.node.orientation.getYaw().valueRadians(), 2)
3.14

'''

def __init__(self, plugins_path='plugins.cfg',
resource_path='resources.cfg'):

unit_test_initialise( self, plugins_path, resource_path )
# Do not initialise the resources.
self._build_scene()



def _build_scene(self):

s_root = self.sceneManager.getRootSceneNode()
self.ninja = UberSpinningNinja(self, s_root, ogre.Vector3(0,0,0))



def render_one(self):
self.frame_started()
self.root.renderOneFrame()
self.frame_ended()

def update_without_render(self):
self.frame_started()
self.frame_ended()

def frame_started(self):
self.ninja.update()

def frame_ended(self):
self.input_manager.capture()

def shutdown(self):
self.input_manager.shutdown()
self.root.shutdown()


class UberSpinningNinja(object):
"""Create a ninja!"""
def __init__(self, app, node, start_coords, entity = False ):
self.node = node.createChildSceneNode("ninja_node", start_coords)
if entity:
self.entity = app.sceneManager.createEntity('ninja', 'ninja.mesh')
self.node.attachObject(self.entity)

src = self.node.Orientation * (ogre.Vector3.UNIT_Z)
directionToGo = ogre.Vector3(0,0,-1)
quat = src.getRotationTo(directionToGo)
self.node.Orientation=quat

self.spinning_x = 0 # 1 for clockwise, -1 for counter clockwise

def start_spinning(self, clock_wise=1):
self.spinning_x = clock_wise

def stop_spinning(self):
self.spinning_x = 0

def update(self, frame_interval = 0.002 ):
self.node.yaw( frame_interval * self.spinning_x)




def _test():
import doctest
doctest.testmod()

def main():
_test()

if __name__ == "__main__":
main()