I've been testing my code behavior using TestNG
and JMockit
for a while now and I have had no specific issue with their combination. Today I came across a situation where I needed to mock one of my internal dependencies, in the so called, type wide manner and I did not need to keep that mock around since none of the test cases dealt with it directly while they counted on the mocked version functionality. So, naturally, I put the mocking logic in my @BeforeMethod
. Here is a sample:
public class SampleTest
{
@Mocked
@Cascading
private InnerDependency dependency;
@BeforeMethod
public void beforeMethod()
{
new NonStrictExpectations()
{
{
dependency.getOutputStream((String)any);
result = new Delegate<OutputStream>()
{
public OutputStream getOutputStream(String url)
{
return null;
}
};
}
};
}
@Test
public void testNormalOperation()
{
// The test whose desired behavior depends on dependency being mocked out
// ..
}
}
But, since my tests do not care about the mocked dependency
explicitly, I'm not willing to declare it as a test class field, unlike what is done above. To my knowledge of JMockit
The only options remaining would be:
Declare dependency
as a local mock field:
new NonStrictExpectations()
{
@Cascading
private InnerDependency dependency;
{
//...
}
}
Declare dependency
as an input argument for beforeMethod()
, similar to what is done for normal @Test
methods:
@BeforeMethod
public void beforeMethod(@Mocked @Cascading final InnerDependency dependency)
{
// ...
}
I see that JMockit 1.6+ would not like the first option and warns with WARNING: Local mock field "dependency" should be moved to the test class or converted to a parameter of the test method
. Hence, to keep everyone happy, I'm ruling this option out.
But for the second option, TestNG
(currently 6.8.6) throws exception when running the test saying java.lang.IllegalArgumentException: wrong number of arguments
. I don't see this behavior with normal @Test
cases passed with @Mocked
parameters. Even playing with @Parameter
and @Optional
will not help (and should not have!).
So, is there any way I could make this work without declaring the unneccessary test class mock field, or am I missing something here?
Thanks
Only test methods (annotated with @Test
in JUnit or TestNG) support mock parameters, so the only choice here is to declare a mock field at the test class level.
Even if not used in any test method, I think it's better than having it declared in a setup method (using @Before
, @BeforeMethod
, etc.). If it were to be possible, the mock would still have to apply to all tests, because of the nature of setup methods; having a mock field of the test class makes it clear what the scope of the mock is.