easymock/easymock — pull request #3 by Todderz (2013-10-20 15:40:15+00:00)
Title: Add qualifier to disambiguate injection

Hello,

I've been going around in circles debating the right way to do the injection. In the end I've scrapped most of the ideas I had, aiming at simplicity.

I had favoured injection by name, but I think your decision to go for injection by type was a good one. Whether by name or by type, eventually you run into some odd cases that require special treatment, but for everything else injection by type allows a clean and simple solution that requires minimal configuration by users, is predictable and unsurprising, and efficient.

Your choice of policy for the injection is actually quite convincing and creates the simplicity and consistency:

* If a mock can be assigned to a field, do it. The same mock an be assigned more than once
* If no mock can be assigned to a field, skip it silently
* If two mocks can be assigned to the same field, return an error

The biggest problem I have with it is the last line, because it disallows using a different mock for each of two fields with the same type.

The simplest way I can see to get around this is to allow an optional "qualifier" element in the Mock annotation, to identify the target field for the injection.

To implement it without making a mess of deeply nested conditionals, I've reorganised the code into some new classes.

First I've pulled your original injection code into a new Injector class. The first real change in the code is that instead of passing a list of mock Objects, we now pass a list of a new Injection class, which holds the mock Object and Mock annotation that describes it.

When we come to injectMocksOnClass, we enlist another new type, InjectionTarget, just to keep things clean.

When checking each mock to see if it can be assigned to the field, we have a slight variation to account for the qualifier:-

* If there is no qualifier, we do the same as before, including rejecting duplicate injection candidates.
* If there is a qualifier, but not matching this field, we just skip this one: It can't be used here.
* If there is a qualifier, we set this mock as the assignment candidate, rejecting duplicates with the same qualifier, but allowing a qualified mock to displace an unqualified mock.

I've added tests for these few cases: Qualifiers distinguish two fields of the same type; A qualified mock displaces an unqualified mock; Duplicate qualifiers on the same type are rejected.

The original injection policy is still true, and all the previous behaviour is preserved, but we add one extra line at the end to clarify what we mean where the first line says "If a mock can be assigned to a field":-

* A mock can be assigned if the type is compatible and, where a qualifier is set, the qualifier matches the field name

For your consideration!

Al