This is a proposal for Cactus v2 ... I have been thinking for some time now about what cactus should become in the future ... During all this email, keep in mind that the overall goal of Cactus is to provide a means to perform unit testing for server side java components, whatever the kind of unit testing. Before we start with the actual proposal, a bit of semantics. I can see 3 types of unit testing :
- logic unit testing, - integration unit testing (unit tests that verifies that the components work together and with the container). This is not full scale integration testing across several subsystem but rather within a given subsystem (which is why it is called integration unit testing) - functional unit testing. This is not exactly acceptance testing. It corresponds to the limit of integration unit testing (end to end test). Acceptance testing correspond more to use case testing and could involve several functional unit tests. However, the biggest difference is on the ownership of these tests. Functional unit tests belong to developers and are there so that developers are more confident that what they implement is what is they understood they should implement. Acceptance tests belong to the customer and are there to verify that the implementation does indeed match the business requirements. Cactus v2 goal is to address these 3 kinds of unit testing in a consistent and flexible manner. What are the main differences with v1 ? Answer : * complete blend of the 3 kinds of unit tests in a single homogeneous and consistent way of writing tests * not only focused on integration unit testing (as it was the case in v1). It will be possible to write Mock Objects style tests that run outside the container with the same framework. You'll be able to use mocks (from www.mockobjects.com for example) if you wish but won't have too as mocks won't need to be written prior to writing the tests * easier to deploy than cactus v1 * add support for a new kind of tests : Pattern Testing. Pattern testing is the ability to verify that the code is applying correctly some patterns. Examples are : - ensure that a Facade pattern is used and that there all code goes through that facade and does not bypass it - ensure that all logging is done by using such Log service and no code is allowed to use System.out for example. Another example is to verify that all jdbc code is found in a data access service. - ensure that all use cases are first handled by a controller (in the MVC model), - ... (the only limit is your imagination !) * works for any existing framework. Cactus v1 had support for only a limited number of APIs : Servlets, JSP Tag libs, Filters, EJB. Cactus v2 supports any existing API out of the box : velocity, struts, turbine, jetspeed, ... * allow for unit testing private methods These are only a few of the advantages of Cactus v2 ... :-). Do you like it so far ? I hope so ... Now, let's stop the marketing and dive into more details. So, where's the magic ? The answer lies in a wonderful new tool called AspectJ (http://www.aspectj.org). Basically it would let you statically (dynamic features are scheduled for version 2 of aspectj) intercept any call before, after or around a given method, making it perfectly suited for unit testing. So what would be the structure of a Cactus v2 test class ? Answer: a test would be an Aspect. The "interception" feature of aspectj will actually let you define where a test start and where it ends. If you decide that the start and end of the test boundaries are in the same method, you'll find the concept of mock objects. If you let it start in a given method and let the test run in its container (possibly up to the database for example), then we find the concept of Cactus v1 integration tests. If the start and end of the test is outside the system, then we find the concept of functional tests. These are only extreme cases but bear in mind that you have total control on where exactly you'd like the test to start and end ! It is in that sense that I say that Cactus v2 would bring together mock objects, integration testing and functional testing. I don't want to show too much of the implementation as it is very much in my head at the current point and it needs to be proved it will work ! I hesitated in writing this email before I had a working prototype to show but I thought that it would still be good to share that little information with you to start getting some feedback from you. Some exemple test cases (just to give some ideas as it will probably change) : // Example of an integration test on an EJB's method using a JdbcDataAccess component to access the database. The test starts in the remote call to the ejb and stops before calling the database public aspect TestXXXAspect extends TestAspect { before(TestRunner runner) : run(runner) && test("testcase1") { // 1 - Use the test runner to get an injector. There will several injectors // http injector, rmi injector, jms injector, ... TestInjector injector = runner.getInjector(TestRunner.EJB_INJECTOR); // 2 - Call test, passing init values if need be. // 3 - Possibly assert results } ResultSet around() : call(JdbcDataAccess.executeSelect(..)) && test("testcase1") { // return mock result set with values for the test return resultSet; } // --------------------------------------------------------------- // Test : mock object style before(TestRunner runner) : run(runner) && test("testcase2") { // 1 - Use the test runner to get an injector TestInjector injector = runner.getInjector(TestRunner.LOCAL_INJECTOR); // 2 - Call test, passing init values if need be. // 3 - Possibly assert results } ... If you want to perform an integration test on a method that is not accessible from the outside, you need an entry point in the container. You can either use a Cactus Proxy or an existing component accessible from the outside. In either case, you would trap the call on the server side and call the method to test : around() : call(MyServlet.doGet(..)) && test("testcase3") { // call the method to test (but from inside the container) // ex: InitialContext context = new InitialContext(); myejbhome = (MyEJB)context.lookup("jndiname"); myejb = myejbhome.create(); // or findby myejb.methodToTest(arg1, arg2, ...); // Assert results } It means that a single test is no longer made up of a single testXXX() method as in junit but can actually be composed of as many "checkpoints" as is desirable (and needed). Note that all this will mean that cactus v2 tests will not be junit test cases. However, it is probably possible to write a wrapper facade (if we wish) so that junit test runners could be used along with existing junit integration tools in IDEs for example. What do you think about all that ? Im' interested in your feedback ! Thanks -Vincent -- Vincent Massol, [EMAIL PROTECTED] OCTO Technology, www.octo.com Information System Architecture Consulting -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
