I have the following set up:
A sample class that needs to be mocked during testing:
@Component
class MyConfig
{
public String getConfig()
{
return "RealValue";
}
}
An interface that defines a single method and has two implementations:
interface MyInterface
{
String myMethod();
}
class MyImpl1 implements MyInterface
{
private final MyInterface delegate;
private final MyConfig config;
public MyImpl1(final MyInterface delegate, final MyConfig config)
{
this.delegate = delegate;
this.config = config;
}
@Override
public String myMethod()
{
return this.getClass().getSimpleName() + ": " + config.getConfig() + ", " + delegate.myMethod() + ";";
}
}
class MyImpl2 implements MyInterface
{
private final MyConfig config;
public MyImpl2(final MyConfig config)
{
this.config = config;
}
@Override
public String myMethod()
{
return this.getClass().getSimpleName() + ": " + config.getConfig();
}
}
A factory class that prepares a bean of type MyInterface
using the MyConfig
object that is a spring bean injected into MyFactory
:
@Component
class MyFactory
{
@Autowired
private MyConfig config;
// Factory method to create the bean.
@Bean(name = "myInterface")
protected MyInterface myInterface()
{
final MyImpl2 myImpl2 = new MyImpl2(config);
final MyImpl1 myImpl1 = new MyImpl1(myImpl2, config);
return myImpl1;
}
// A simple getter that prepares MyInterface on the fly.
// This is just to demonstrate that getter picks the mock where as
// the factory bean doesn't
public MyInterface getInterface()
{
final MyImpl2 myImpl2 = new MyImpl2(config);
final MyImpl1 myImpl1 = new MyImpl1(myImpl2, config);
return myImpl1;
}
}
A simple test case that checks if the mock version of MyConfig
is getting into the bean created using @Bean
or not:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:application-context.xml"
})
public class SpringBeanMockExampleTest
{
@Mock
private MyConfig config;
@InjectMocks
@Autowired
protected MyFactory factory;
@Resource
private MyInterface myInterface;
@Before
public void setupMocks()
{
MockitoAnnotations.initMocks(this);
}
/**
* Fails as the return value is "MyImpl1: RealValue, MyImpl2: RealValue;"
*/
@Test
public void testBean()
{
Mockito.when(config.getConfig()).thenReturn("MockValue");
Assert.assertEquals("MyImpl1: MockValue, MyImpl2: MockValue;", myInterface.myMethod());
}
/**
* Assertion passes here.
*/
@Test
public void testGetter()
{
Mockito.when(config.getConfig()).thenReturn("MockValue");
Assert.assertEquals("MyImpl1: MockValue, MyImpl2: MockValue;", factory.getInterface().myMethod());
}
}
I expected the testBean
method to pass also, but obviously the mock is not getting injected into the factory bean created in MyFactory
.
It seems the mocks are replacing the actual beans after the factory bean creation step is completed. Due to this, the reference in factory beans is not updated with the mock.
How can I fix this so that testBean
works as expected?
Aucun commentaire:
Enregistrer un commentaire