Funnily enough I spent Tuesday working out a solution for this kind of issue for a Cocoon Action I'm working on at the moment.

I went for a 'mock' object approach [see <http://mockobjects.sourceforge.net/endotesting.html>], creating mock versions of (for my case) Redirector, Request, Session, Source and SourceResolver. These all represent the simplest possible implementations of the interfaces, which pass back results that I pre-set with additional set methods. I like this approach because it's very simple, very flexible and transparent, and the mock objects can potentially grow in the source base alongside the test cases.

Here's an example of a bit of one of the resulting testcases:

public class SessionHandlerTest extends TestCase {

    private SessionHandler handler;
    private SessionMock session;
    private Redirector redirector;
    private SourceResolver sourceResolver;
    private RequestMock request;
    private Parameters parameters;
    private Map objectModel;

    public SessionHandlerTest(String name) {
        super(name);
    }

    public void setUp() {
        this.handler = new SessionHandler();
        this.session = new SessionMock();
        this.redirector = new RedirectorMock();
        this.sourceResolver = new SourceResolverMock();
        this.request = new RequestMock();
        this.parameters = new Parameters();
        this.objectModel = new HashMap();
        this.objectModel.put(Constants.REQUEST_OBJECT, this.request);
    }


/**
* Check that a form field of "login=sessionHandler" is required for successful
* login.
*/
public void testActLoginSessionHandlerField() throws Exception {
setupValidLoginAttempt();
this.request.mockRemoveParameter("login");
Map map = handler.act(this.redirector, this.sourceResolver, this.
objectModel, "src", this.parameters);
assertNull("Action should return null to indicate rejected login"
, map);
}



private void setupValidLoginAttempt() { this.request.mockSetParameter("login","sessionHandler"); this.request.mockSetParameter("username","valid"); this.request.mockSetParameter("password","user"); this.parameters.setParameter("accept-login","true"); this.parameters.setParameter("require-secure-login","true"); this.parameters.setParameter("required-login- parameters","username,password"); this.session.setAttribute("sessionhandler/original_uri","testpage" ); this.request.mockSetSecure(true); this.request.mockSetSession(this.session); }

My personal feeling is that setting up specialized TestCases for testing, whilst it may simplify the code of tests for people familiar with the code,
removes transparency and adds a level of complexity into the test cases that could make them harder to maintain. e.g. you need to look at the definition of the new TestCase in order to determine what the pre-set state is and then learn the new methods for altering it. With plain Mock classes you have to explicitly setup everything in the TestCase which may require more lines of code (but then you can easily do a copy and paste job from a previous test case), however, you end up with a test case that is self contained and self documenting. The only new methods you need to learn are additional methods in the mock classes that provide setup or validation functionality.


Stuart.

PS. I'm intending feeding back the mock objects to Cocoon if folk are interested.


On Thursday, August 9, 2001, at 06:31 am, giacomo wrote:


I've followed the discussion about dropping Testlet in favor of JUnit with great interest.

What I think is missing in this area of unit tests of Avalon
components are specialized TestCases.

The idea came when I was looking at the DataSourceTestCase (and wanted
to adapt it for my own components). When one needs to test Components
you'll mostly need to create a logger (Loggable), maybe a Context
(Contextualizable), a Configuration object (Configurable) and sometimes
also a ComponentManager (Composer). And at least here where you have to
test a Composer you probably wish to have a CM setup easily. This is
what the aforementioned TestCases should set up for you.

If there is interest I'd like to contribute specialized JUnit
TestCases for Avalon. I initially thought of two TestCases:

FrameworkTestCase (uses framework.component.DefaultComponentManager)
ExcaliburTestCase (uses excalibur.component.ExcaliburComponentManager)

The discussion I'd like to make is about how things like Context,
Configuration (be it an already created Configuration object, a String
or a File containing the configuration) and the roles got passed into
the TestCase for setup of the CM. The possibilities are:

Constructor:
        This would set it up once for every test in the class but
        gives no possibility to change it (ie. Configuration,
        Context) for different tests.

separate method:
        This would allow to use it as a test case itself and it
        could be called every time you need to change something.

setup/tearDown method:
        This would set up the CM for every test (including disposing
        of the component itself in the tearDown method) but also no
        way to use different configs for different tests in the same
        TestCase.

Thoughts?

Giacomo


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



-------------------------------------------------------------------------
Stuart Roebuck                                  [EMAIL PROTECTED]
Lead Developer                               Java, XML, MacOS X, XP, etc.
ADOLOS                                           <http://www.adolos.com/>

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to