如何使用@Transactional方法将jmockit的模拟对象注入弹簧管理对象?

时间:2014-03-19 06:23:51

标签: java spring unit-testing transactional jmockit

我正在Spring项目中编写一个TestNG测试用例,并使用jmockit来模拟依赖项。我遇到一个问题,就是我无法使用Deencapsulation.setField来设置对包含@Transactional方法的spring-managed对象的依赖,错误是:

  

在类java.lang.reflect.Proxy

中找不到名称“dataLogManager”的实例字段

我在此处列出了示例代码,

测试用例:

public class QueueManagerTest extends AbstractTestNGSpringContextTests {
    @Autowired  
    private QueueManager queueManager;

    @Autowired
    private ApplicationContext context;

    @Autowired  
    private TransInfoManager transInfoManager;

    @Autowired
    private Generator generator;

    @Autowired
    private MessageDTOFactoryBean messageDTOFactoryBean;

    @Test(description="單元測試:寫入一筆Data資料,非邊界情況下(無待處理筆數)")
    public void writeControlMessage(            
        @Mocked final TransInfoManager transInfoManager,
        @Mocked final DataManager dataManager,
        @Mocked final DataLogManager dataLogManager
        ) {
    ....
        Deencapsulation.setField(queueManager, "dataLogManager", dataLogManager);
        Deencapsulation.setField(queueManager, "dataManager", dataManager);
        Deencapsulation.setField(queueManager, "transInfoManager", transInfoManager);
    ....
    }
}

服务:

@Service
public interface QueueManager {         

    @Transactional
    MessageDTO putDataIntoQueue(MessageDTO message);

}

有谁知道如何解决这个问题?谢谢。

1 个答案:

答案 0 :(得分:1)

如果您要测试的是一些实现QueueManager接口的特定类,那么解决方案就是直接在测试中实例化该类,而不是使用Spring。

异常的原因是Spring实际上为queueManager字段创建了一个代理类实例,用于修饰实际实现(代理对象将每个方法调用委托给另一个对象) ,这将是实际实现QueueManager接口的应用程序类的实例。代理类不包含名为" dataLogManager"的字段,因此Deencapsulation.setField(...)无法找到它。

如果我提到的第一个解决方案不适用,你仍然可以让Spring进行实例化,前提是它还会在queueManager对象中注入字段。要模拟实现DataLogManager(和其他接口)的类,请使用@Capturing代替@Mocked(或除此之外){{1}};这将指示JMockit将模拟扩展到所有实现类。