I have so controller
@Controller
public class MyController {
@Autowire
MyClass myClass;
//myClass doesn't have setter and getter
....
@RequestMapping("/path")
public String underTest(){
myClass.makeSomething();
return "html.jsp"
}
I want make mock test using Mockito and mock myClass.
In test class I want get myClass so:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/BeanConfig.xml");
myClass = context.getBean("myClass ", MyClass .class);
But I need autowire this bean to Controller for testing controller's method(I think test code should not affect to normal code).
There are exist way to make it without writing of set method?
I want to check that myClass.makeSomething() invokes once in method underTest.
I'm not sure I agree with you that test code should not affect normal code. I think an entirely valid reason to refactor / rewrite production code is to make it more testable (this is probably achieved by making it more modular, which is generally a good thing anyway).
This is precisely why annotations like
@VisibleForTesting
exist. Then you can create a package-local setter for MyClass, add the above annotation (for information to other programmers and possibly code inspection tools) and set the field in your test (which should reside in the same package).
Alternatively, since you are using Mockito, you could simply annotate the MyController instance with @InjectMocks, eg
@Test
public class MyControllerTest {
@Mock
private MyClass mockMyClass;
@InjectMocks
private MyController myController;
@BeforeMethod
public void before() {
MockitoAnnotations.initMocks(this);
}
// do tests...
}
Note that @InjectMocks does not depend on any annotations on the target field (i.e. @Autowired, @Resource, @Inject etc). It just works. (Presumably you will still need those annotations for Spring injection, so don't remove them! The point is you can also use it for fields that aren't annotated).
Note also that, depending on which version of Mockito you are using, you may need to instantiate the MyController in the before() method before calling MockitoAnnotations.initMocks()
As long as your test for MyController
resides in the same package as MyController
itself (as it's usually done - same packages in different source folders), you can simply assign it:
MyController controller = new MyController();
controller.myClass = mockMyClass;
That's the reason not to put @Inject
/@Autowired
on private
fields.
Try testing the controller directly with context.getBean(). MyClass will be autowired into it.
I agree with @axtavt's answer, however if you absolutely want to go your way with injecting the mock in an integration test, you can do this:
define a overriding bean configuration file, say bean-test-config.xml, with content along these lines:
<import resource="classpath:spring/BeanConfig.xml"/>
<bean name="myClass" factory-method="mock" class="org.mockito.Mockito">
<constructor-arg value="MyClass"></constructor-arg>
</bean>
This should correctly inject in a mock in your controller. You will have to get hold of this mock in your test and inject in any behavior that you are expecting from this mock though.