Releases: sbabcoc/JUnit-Foundation
Add test lifecycle events for theory method permutations
This release expands on Theories runner support, adding test lifecycle event notifications for Theory method permutations. Without JUnit Foundation, these notifications are entirely absent - including AssumptionViolatedException events, which reveal data points that were rejected by @Theory
methods as inapplicable.
Several chunks of code-generation magic were required to add these permutation events:
- The
methodBlock
method is intercepted. For theory methods, the actual class runner statement is stored and a "lifecycle catalyst" statement is returned instead. This enables the interceptor declared in the RunWithCompleteAssignment class to manage the execution of the actual statement. - The
runWithCompleteAssignment
method is intercepted. The "lifecycle catalyst" created by the MethodBlock class attaches the class runner to the thread and creates a new atomic test for the target method. The actual method block statement is retrieved from MethodBlock and executed, publishing a complete set of test lifecycle events. - The
describeChild
method is intercepted. For theory permutations, a unique ID is generated from the method name and arguments. This unique ID is injected into the description, allowing it to be used as a distinct "key" throughout the method lifecycle. - Tracking was added to the
run
method interceptor to retain a mapping of parent runners to the notifiers that were provided to them. - Tracking was added to the RunAnnouncer listener to retain a mapping of method descriptions to their corresponding atomic test objects.
This release also includes various other theory-related revisions and optimizations of existing implementation. Share and enjoy!
Add support for the Theories runner
This new release adds support for the Theories runner. This runner enables you to implement "theory" methods (a parameterized equivalent of standard "test" methods) and have them executed against defined data points. Theory methods can define assumptions that will skip inapplicable data points.
NOTES ABOUT THE THEORIES RUNNER:
- The granularity of run notifications for theory methods is per method, not per iteration as would be the case with other parameterized runners. This can be worked around via the events published by the MethodWatcher facility.
- Iteration of defined data points terminates upon encountering any failure, even if there are data points that have yet to be tested against the current theory.
Upgrade JUnit version from 4.12 to 4.13.1
After years in stasis, the JUnit Team decided to push a batch of queued-up changed in a new release. I missed the first one (4.13), but I'm catching up to the latest here. Fortunately, it doesn't appear that any of the revisions were fundamental enough to break my crazy code generation hooks.
Consolidate attachment of RunListener service providers
In this release, I consolidated the attachment of standard JUnit RunListener service providers with the enhanced notification interfaces defined by JUnit Foundation. This enables implementers to declare all of their service providers in a single common configuration file, entirely eliminating redundancy. Note that per-interface configuration files are still supported for backward compatibility.
Add JUnitParams unit test and documentation
This release is essentially just wrapping up from the prior release. Support for the JUnitParams
runner was deployed in version 12.1.0 of JUnit Foundation. The unit test will ensure that no one breaks this support without noticing, and the README documentation will help users figure out how to use this support to capture test method parameters.
Improve tracking and publication of ReflectiveCallable objects
This release fixes a fundamental deficiency with my initial attempt to record and publish ReflectiveCallable objects. Saving these in the AtomIdentity object and publishing from there wouldn't have worked for atomic tests with configuration methods. I now record every "callable" object with its associated JUnit framework object.
I also fixed the handling of ignored tests, generating an AtomicTest object to send with the notification.
NOTE: This is a breaking change, and I should probably advance to the next major version, but the feature I broke is so obscure that I marked it as a feature release instead.
AtomicTest: Implement 'equals' and 'hashcode' methods
In order for AtomicTest objects to be used as hash keys, this class needs to provide implementations for the equals
and hashcode
methods. This release adds these methods.
Enhance RunWatcher notifications and ArtifactParams feature
In this release, I revised the way I associate test method Description
objects to atomic tests to ensure that the notifications I send to RunWatcher
service providers include the descriptions that were used when the associated methods were actually invoked. This resolves an inconsistency related to the JUnitParams
test runner.
I also enhanced the ArtifactParams
feature, adding code in RunReflectiveCall
to record the "callable" object in the AtomIdentity
test watcher. This object is a closure which may contain the parameters that were supplied to the actual test method. This enhancement can greatly simplify the implementation of the getParameters()
method of the ArtifactParams
interface.
Add a few more 'null' checks
There were a few spots RunAnnouncer
where we were at risk for triggering NullPointerException
failures. This release add 'null' checks to prevent these failures.
Consolidate watcher declarations into a single SPI configuration file
This release consolidates the declaration of JUnit Foundation service providers into a single configuration file. Support for the previous file-per-interface approach is retained to provide backward compatibility.
One significant benefit to switching from ServiceLoaders to pre-initialized unmodifiable lists is that I no longer need to synchronize my iterators. The code is therefore smaller and less complicated.
Another benefit is that we no longer end up with multiple instances of each service provider that implements multiple interfaces. Previously, a separate instance would be created for each implemented interface.
NOTE: If you have a project with JUnit Foundation service provides that was created prior to this release, your current file-per-interface SPI configuration files will continue to be recognized, and you still get the benefit of proper handling of service providers that implement multiple interfaces. However, we recommend that you take this opportunity to consolidate all your SPI configurations into the common file:
META-INF/services/com.nordstrom.automation.junit.JUnitWatcher