@Repository
public class FakeRepository implements FakeRepositoryInteface {
@Autowired
private FakeDaoInterface dao;
public void doStuff() {
dao.doStuff();
}
}
public inteface FakeRepositoryInteface {
void doStuff();
}
@Repository
public class FakeDao implements FakeDaoInterface {
public void doStuff() { }
}
public interface FakeDaoInterface {
void doStuff();
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=ContextLoader.class)
public class FakeRepositoryTest {
@Autowired
private FakeRepositoryInterface repository;
private Mockery context = new Mokery();
@Test
public void doStuffTest() {
// aqui eu moko meu dao com JMock crio as regras como ele deve trabalhar
}
}
Agora a grande dúvida, no teste eu tenho o atributo repository injetado pelo spring com o @Autowired, dentro desse objeto ele injetou para mim um objeto do tipo FakeDao (FakeDaoInterface)tbm via @Autowired. Esse objeto dao foi “mokado” com o JMock, ai preciso substituir o objeto que já foi injetado.
Então, não rola colocar um setDAO na minha DAO, porque na minha classe FakeRepository eu tenho uma classe Proxy injetada pelo Spring, essa classe proxy só consegue fazer chamadas aos métodos da interface onde ela é injetada, para usar o setDAO eu teria que colocar ele na interface FakeRepositoryInteface (nojento).
To seguindo o seguinte caminho:
@Before
@SuppressWarnings({"deprecation", "unchecked"})
public void init() {
Class<FakeRepository> clazz = AopProxyUtils.getTargetClass(repository);
FakeDaoInterface fakeDao = context.mock(FakeDaoInterface.class);
try {
Field field = clazz.getDeclaredField("dao");
field.setAccessible(true);
field.set(clazz, fakeDao);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
Esse método é chamado antes das chamadas aos meus métodos de teste @Before, o método AopProxyUtils.getTargetClass(Object) é deprecated, ele me retorna o Class do objeto que o Proxy está interfaciando, ou seja, FakeRepository dessa forma consigo acesso a todos os Fields, Methods, etc. Dessa forma consigo acesso ao meu atributo dao na classe FakeRepository, mas tem um problema, esse método de inicialização dá erro na hora de setar o valor do field b[/b] porque devevira passar um objeto do tipo FakeRepository e não consigo fazer o casting do meu objeto clazz.
Alguém conheçe alguma classe utilitária que consiga fazer esse Casting? Ou qualquer solução mirabolante!!!
Que tal rodar este teste sem spring (tirando @RunWith e @ContextConfiguration) e injetando a dependência manualmente (usando ReflectionTestUtils, por exemplo)?