Chris said:
Andrew McDonagh wrote:
There is much behaviour which is not observable. That is to say not legally
observable according to the laws of the Java language. For instance:
UNit tests test the result of a call, of which there has to be some
output, else the code isn't doing any thing useful.
Note: All of the following answers rely upon normal Java access
privileges and do not assume the need to use any kind of reflection.
1) any non-public member variable
If the ClassUnderTest (CUT) has a private member var that changes as a
result of the test AND its change is the result that will tell the test
if its passed, then we will need to somehow see that variable in one
form or another. In other words, the CUT would normally have some other
method that could be called to see if the private member has changed
(note not talking solely about a simple getter here - but it may be the
case).
The change may be that the private member has been nullified - in which
case, by stimulating the CUT again we can check for change.
An example here would be having a Listener reference. Our test could
give the CUT a MockListener which we verify is called when we stimulate
as necessary, then call the public method to set the listener var to
null then stimulate the CUT again and check the MockListener was NOT
called a second time.
Either or any other way, if a CUT is changing the state of a member var
and that change has no effect, then the member var is not needed - and
so delete it.
2) any aspect of an object's state that is only reflected in
its non-public behaviour
Can you give me an example of what you mean here, because I'd say that
state was not needed if it can't be detected from outside.
3) any part of the execution state of another thread
4) the locked/unlocked status of a monitor
Testing the state of execution of another thread, multi-threadness and
other threaded scenarios are not a unit tests, they are functional (ALA
Acceptance) tests.
These types of test are not what Junit was developed for and so 'out of
the box' it isn't supported very well. That being said that are add-ons
to do just those types of tests.
The main reason they were considered to be part of the unit testing
stage, is that they test functionality of the system, rather than the
behavior of a Unit (Class). Acceptance/Functional tests are better
developed in other testing tools that support a scripting interface that
non-java developers can read, understand and use themselves to help
create tests (See FitNesse.org, Selenium, Watir, etc)
We would not normally write tests to detect monitor status itself, but
we could write tests to prove we don't get deadlocks.
Unit tests test individual classes/methods.
There are probably others. I would expect the first two of these to be the
most problematic in practise.
Weird, to me they are the easiest.
Additionally, there may be external restrictions -- e.g. it may be possible for
an application to log a message but not (without artificially boosting its
privileges) be permitted to read the resulting log.
A unit test is not a unit test if it relies upon external resources
and/or restrictions that can not be substituted at runtime - they are
acceptance tests.
In the example above, the unit test could very easily substitute the log
object the class (not the application - cause then we are acceptance
testing) is writing to, so it can verify the correct behavior.
This dependency injection (via constructor, setter, dynamically loaded
from resource file, retrieved from a singleton, etc) necessary for
testability results in a better more changeable & maintainable design.
If this seems strange, feel free to knock up an SSCEE (or what ever its
called this week) example to which you have something that is
non-visible and so can't test and I'll show you how it could or if its
not a unit test.
Andrew