Here are propositions for making IC and MO tests interchangeable, i.e. to be
able to run a given test case either in MO mode or in IC mode without having
to modify it !
Note: During the rest of the mail, we'll assume well' dealing with the
Servlet API (but the ideas would be the same with JSPs, Taglibs, Filters,
EJBs, ...).
* Premise 1 : All HTTP parameter initialization (Cookies, HTTP headers, HTTP
parameters, HTTP method (GET, POST,..), ... will need to be initialized in
beginXXX() for all kind of tests (MO, IC, PF).
* Premise 2 : We need an interface above the standard Servlet API. This is
because MO tests need new methods to initialize the state of the implicit
objects. For
example, there need to be a
"ServletConfigWrapper.setupAddInitParameter(String name, String value)" to
add an init parameter that would normally have been defined in web.xml. This
is also to override existing container behaviours (like
HttpServletRequest.getRequestDispatcher(String relativePath) that need to be
overriden to take into account the WebRequest.setURL() values).
All implicit objects stored in XXXTestCase classes will be of that wrapped
types (i.e. HttpServletRequestWrapper, HttpServletResponseWrapper, ...).
These wrapper will of course implement the standard API interfaces.
* Premise 3 : In order to be able to define different init values for
different test cases, we need to expand the current Cactus web.xml mapping
mechanism (see next email for proposition on how to do this).
* Premise 4 : What happens when cactus encounters a
"ServletConfigWrapper.setupAddInitParameter(String name, String value)" call
in testXXX() and when in IC mode ? Indeed, this is how tests will be written
in MO mode, so if we don't touch the code, it will also be executed in IC
mode.
Premise 4, Solution 1 : Force MO tests to define init data in a web.xml file
in the same way that IC tests do. This is a bit more cumbersome to write but
is consistent with IC tests. Persons who only wish to write MO tests (No IC
tests) will find this a PITA though ...!
Premise 4, Solution 2 : Apply the following algorithm when in IC mode :
- if the config data is already defined (i.e. it has already been defined in
web.xml), then ignore the call to
"ServletConfigWrapper.setupAddInitParameter(String name, String value)". If
not, then :
Premise 4, Solution 2a : raise an exception saying that the parameter should
have been defined in web.xml
Premise 4, Solution 2b: save the parameter value as in MO mode. Meaning that
the corresponding getter will return this mocked parameter instead of a real
one coming from web.xml.
Solution 2a is good because strict and avoid thinking that a test is 100% IC
when it is not (imagine the situation where I have first written an MO style
test and then I want to run it in IC mode but I forget to add the init for a
parameter in web.xml. The test will still run but the parameter will be
simulated). However, this simply means that we are not testing the passing
of parameter from web.xml to the container in real and sometimes the user
will not care to verify this part ... (in which case Solution 2b will be
preferred) ...
* Warning : Even if MO and IC tests are technically interchangeable, I
believe that some of the tests will really be interchangeable and some
others won't simply because it does not make sense ... For example, let's
imagine I have a method that make use of a domain object. In MO style, I
will create a mock implementation of this domain object and find a way to
insert it in my class to test so that it will use this mock object instead
of the real one. This is because MO are used to test in isolation. However,
when performing IC tests, I would probably want to use the real domain
object (to ensure interactions between objects work) ... so in effect I
would have 2 different tests that are not really interchangeable ...
Another example is a database connection. In MO style I may mock the
database connection and I would be able to run my unit tests on my developer
machine with no database whatsoever ... In IC test, I might want to actually
use a test database. If I write this IC test and then try to run it in my
machine, it will fail ...
Conclusion: even though IC and MO would be technically interchangeable, all
tests won't be in practice ... ! :-)
Apart from that, the premises defined above should lead to tests
technically interchangeable.
Thanks
-Vincent