Repository: mockito/mockito
Issue: Add ElementType.PARAMETER to @Mock
Labels: enhancement

Parameterized tests are becoming more common - JUnit 5 explicitly allows parameters and the sample [MockitoExtension](https://github.com/junit-team/junit5-samples/tree/master/junit5-mockito-extension/src/main/java/com/example/mockito) currently includes an @InjectMock to trigger the creation of a mock parameter.  It would be so much cleaner to use @Mock in both places.

This shouldn't be an issue for most legacy test systems since they don't allow test parameters (by default). 


Issue comments:
@smoyer64 I think that is a reasonable addition. Do you maybe have a sample JUnit test case that I can add to our test suite as regression test?

@TimvdLippe,

Will this change be going into Mockito 1.x or 2.x (or both)?

@sbrannen Mockito 2.0. We might be able to port back to Mockito 1.x but I would prefer not to. Is there an explicit requirement for this change to be included in 1.x?

Regarding a regression test, this should do the job!

``` java
import static org.junit.Assert.assertTrue;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.junit.Test;
import org.mockito.Mock;

/**
 * It's actually sufficient if this class compiles. The test methods
 * are therefore a bit superfluous.
 *
 * @author Sam Brannen
 */
public class MockAnnotationDeclarationTests {

    @Mock
    String foo;

    void bar(@Mock String baz) {
    }

    @Test
    public void mockAnnotationCanBeDeclaredOnField() throws Exception {
        Field field = getClass().getDeclaredField("foo");
        assertTrue(field.isAnnotationPresent(Mock.class));
    }

    @Test
    public void mockAnnotationCanBeDeclaredOnParameter() throws Exception {
        Method method = getClass().getDeclaredMethod("bar", String.class);
        assertTrue(method.getParameters()[0].isAnnotationPresent(Mock.class));
    }

}
```

So feel free to use that.

Cheers,

Sam

@TimvdLippe,

I don't suppose there is an explicit _requirement_ per se to have this support in 1.x; however, I feel it could well benefit 1.x users who also wish to use JUnit 5. Furthermore, I cannot foresee any possible negative side effects for 1.x users: it's 100% backwards compatible.

I do not think we really have an infrastructure to still publish Mockito 1 artifacts. We did however not change much in 2 and 99% of all Mockito code should run as expected after updating. Mainly, we removed deprecated code that people had years to upgrade.

I think adding this should be okay even though there is no scenario where Mockito itself would process the annotation. Would adding an annotation to the JUnit plugin not be another altivertive? I wonder if that was a cleaner solution.

> Would adding an annotation to the JUnit plugin not be another altivertive? I wonder if that was a cleaner solution.

Introducing a new annotation in Mockito's official JUnit 5 support is of course technically possible -- that's what our proof-of-concept `MockitoExtension` does today (i.e., we created an `@InjectMock` annotation).

But... I don't think I would call that a _cleaner solution_. IMHO, a single annotation from Mockito would be the cleanest solution since it would result in the **element of least surprise** for users of Mockito.

FWIW, we have already hashed out the [exact same discussion for the Spring Framework](https://jira.spring.io/browse/SPR-14057) with regard to Spring's `@Autowired` annotation. Previously, it was not allowed to be declared on a constructor or method parameter, but we changed this for Spring 4.3.

Ok, considering that JUnit and Mockito is such a common combination, let's just make it as easy as possible.

Sounds good! 👍 

Wow ... a lot of work got done while I was out celebrating Father's Day.  From a user's perspective, this all looks perfect.  How often do you get everything you ask for?  I guess I have one final  question which, since this issue is closed, is more academic - where should an official, production ready MockitoExtension for JUnit 5 be hosted?  MockitoJunit is obviously part of the Mockito project and the MokitoExtension will always rely on both Mockito and JUnit 5.

Maintaining the status quo would be fine, but it might also make sense to create a junit5-extensions project for "common combinations" (using the wording above), where a combination of project maintainers could collaborate on code that is essentially the intersection of their projects?  External Extensions and TestEngines are going to be documented in the JUnit 5 wiki per issue https://github.com/junit-team/junit5/issues/297 and, given the collaboration demonstrated by this thread, maybe the whole question is moot.

In any case, thanks for all the hard work that's gone into both projects!

@smoyer64 You got lucky we are working hard on releasing Mockito 2.0 :smile: 

I am not sure what the stance is of the JUnit team regarding such extensions. Could you open an issue on JUnit5 to discuss where such extensions should be placed?

@TimvdLippe 

The question has been posed to the JUnit 5 team in issue https://github.com/junit-team/junit5/issues/321.  @sbrannen is a member of that team, so I'm guessing he's already seen the question ;).  And I'm just one of those pesky users (trying to help identify use cases and stress-test the new code)!

Thanks a lot. Looking forward to their response.


Pull request review comments:
Awesome! 👍 


Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/Mock.java b/src/main/java/org/mockito/Mock.java
index 91cb0538c8..2988cb2cba 100644
--- a/src/main/java/org/mockito/Mock.java
+++ b/src/main/java/org/mockito/Mock.java
@@ -9,6 +9,7 @@
 import java.lang.annotation.Target;
 
 import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
@@ -58,7 +59,7 @@
  * @see MockitoAnnotations#initMocks(Object)
  * @see org.mockito.runners.MockitoJUnitRunner
  */
-@Target(FIELD)
+@Target({FIELD, PARAMETER})
 @Retention(RUNTIME)
 @Documented
 public @interface Mock {


Test patch: