============================================================================
======================
OVERVIEW:
I have been trying to write a test harness for an active object with little
success. The active object I have been trying to test is actually the
socketengine of the sockets example provided in the Series 60 SDK
distributed by Nokia. It is one of the Nokia provided examples and as such
the SDK documentation provides quite a bit of discussion and diagrams to
help understand the code.
To initially start testing I have made use of Nokia's testframe example code
provided in the Series 60 SDK. Although this does not provide everything
one might want in a unit test framework, it does make for a good starting
point. Furthermore, it too is well documented in the Series 60 SDK.
So not only are the important parts of my example well documented, they are
likely code you are already familar with. This may very well help someone
trying to answer this post.
An important, yet subtile, aspect of the particular problem is the way in
which the Series 60 emulator is configured to work with the Windows
development PC's network connection. In the SDK documentation there is a
description of how to configure a Windows 2000 box using a null modem cable
entitled "Enabling RAS for the emulator". For development on a Windows XP
platform this is known not to work, but a very similar approach using a
serial port emulator does. (The details of setting up a Windows XP platform
can be found in the Nokia forums at
http://nkn.forum.nokia.com/devrel/threadshow.cfm?mb=7038809959063292&msg=451
89640892&page=1 entitled "Network from emulator without cable - FINAL
SOLUTION HERE !!!".) I have attached a document containing the crux of this
posting.
The most relevant aspect of the communications configuration is that in both
cases (both Windows 2000 and Windows XP) it is necessary to run the
commsdb_ras command which sets up two access points in the comms database
("RAS NT" and "Linux RAS"😉. When running Nokia's sockets example there is a
dialogue that pops up asking one to choose between one of the two access
points.
My objective is to understand how to write a unit test for an active object,
even if the active object under test is responsible for using other active
objects.
============================================================================
======================
DETAILS:
I have taken two approaches worth mentioning here. With both I have
encountered show stopping problems I do not understand how to overcome.
Although I describe my overall approach in both cases, you will likely need
to look at the code to really understand what I am doing.
----------------------------------------------------
APPROACH A (mar3.zip):
The most recent approach is the following:
*Create a custom active scheduler that overrides the WaitForAnyRequest()
method and have this scheduler call CActiveScheduler::Stop whenever there
are no more outstanding requests on the current thread. (I have also tried
minor variations on the WaitForAnyRequest() method such as ignoring the
results of RThread().RequestCount() on the first pass.)
*Create a separate thread within the test code and install the custom active
scheduler. After starting the new thread the parent thread uses
User::WaitForRequest() to block until the new thread completes. (Actually I
use a wrapper around User::WaitForRequest() that contains a timeout
feature.)
*Within the new thread initalize the active object under test and make an
async. request to it. (Call socketsEngine->ConnectL() in my example).
After doing this call CActiveScheduler::Start() which should only return
when the custom active scheduler has deemed there are no more outstanding
requests and called CActiveScheduler::Stop().
*The new thread exits, and the parent thread continues on to the next test.
*In either the new or the original thread the results of the active object
under test should be compared to expected results. This is not done in my
example since I never got the whole mechanism to work in the first place.
----------------------------------------------------
PROBLEMS ENCOUNTERED WITH APPROACH A:
The construction of CBase objects fail when calls to CleanupStack::PushL()
leave. This was thought to be due to a lack of a clean up stack in the new
thread. Unfortuantely, creating one didn't solve the problem (CTrapCleanup*
cleanup = CTrapCleanup::New()).
----------------------------------------------------
APPROACH B (feb27.zip):
Prior to approach A I tried the following different but similar approach.
*Create a CActiveObjectTestUtililty class that will create a separate thread
and install a custom active scheduler.
*The active scheduler of approach B is basically the same as that in
approach A, except it was responsible for making the async. requests to the
object under test via a fancy callback mechanism to the test code.
*The majority of approach B is basically that of approach A.
Although approach B started out much different than A, but by the time of
the code snapshot the ancestry is fairly clear. You will see from a large
amount of commented out code that my attempts have evolved over time.
----------------------------------------------------
PROBLEMS ENCOUNTERED WITH APPROACH B:
Although I had no problems with the clean up stack (after learning I had to
create my own within the new thread) the program blows up after leaving the
CActiveObjectTestScheduler::WaitForAnyRequest() method. It is worth
metioning that the access point selection dialogue does pop up, and activity
on m-Router can be seen after selecting the NT RAS access point.
----------------------------------------------------
NOTES ON THE CODE:
My bld.inf files have both PRJ_MMPFILES and PRJ_TESTMMPFILES entries and as
such you will need to use the "test" argument to abld to completely build
the code.
i.e.:
>bldmake bldfiles
>abld build wins udeb
>abld test build wins udeb
>abld makefile vc6
>abld test makefile vc6
The zip file labeled feb27.zip is approach B, and the file labeled mar3.zip
is approach A.
For whatever reason, it is important to open the testframe project first in
MS Visual Studio before adding the others. If you don't do this it is
difficult (maybe impossible) to set breakpoints that are not disabled when
the debugger starts.
If you are not already familar with the testframe example code, you need to
know that all the custom stuff is only in the RunTestsL() method of the
CTestExecutor class. Look here to place your first breakpoint.
============================================================================
======================
SUMMARY:
I am a bit lost as to why I am having as much difficulty testing active
objects as I am. I suspect part of my problem has something to do with the
access point dialogue not being controlled by the same process as my test
(which I know in the emulator is really just another thread). I am also
very frustrated by the lack of any good example showing how to properly unit
test an active object.
Any help would be greatly appreciated.
Sincerely,
James Carpenter
Email: [email protected]
AOL IM: nawkboyrules