我有一个在规则中使用服务类的drools规则文件。所以一个规则做这样的事情:交易注释避免被模拟的服务
的eval(countryService.getCountryById(1)!= NULL)
在validationservice被注释与@Service和@Transactional(传播= Propagation.SUPPORTS)Drools的文件在无状态知识库中使用,并添加应该在流口水中使用的事实。一旦完成,会调用session.execute(facts)并启动规则引擎。
为了测试规则,我想存根countryOK.getCountryById()。使用mockito没有大问题。对于使用drools设置的其他服务完成此操作,并且它工作正常。然而在这个特殊的情况下,countryService并不存在,我不知道为什么。花了很多时间并检查我的代码之后,我发现在服务之上有@Transactional或者缺少这个注释会产生差异。缺乏@Transaction使得mockito模拟countryservice没有任何问题,因为@transactional导致mockito失败(没有任何错误或提示)注入模拟,以便使用原始的countryservice对象。
我的问题是为什么这个注解导致这个问题。为什么不能在@Transactional设置时注入mockito?我注意到,在的Mockito失败,当我调试和检查countryService当它被添加为全局Drools的会议上,我看到下面的差异,当我检查我的debugwindow的countryservice:
与@事务:countryService具有值countryService $$ EnhancerByCGLIB $$ b80dbb7b
而不@Transactional:countryService具有值countryService $$ EnhancerByMockitoWithCGLIB $$ 27f34dc1
此外与@t ransactional我在countryservice方法的断点getCountryById被找到并且调试器停在那个断点处,但没有@transactional,当mockito绕过它时,我的断点被跳过。
ValidationService:
@Service
@Transactional(propagation=Propagation.SUPPORTS)
public class ValidationService
{
@Autowired
private CountryService countryService;
public void validateFields(Collection<Object> facts)
{
KnowledgeBase knowledgeBase = (KnowledgeBase)AppContext.getApplicationContext().getBean(knowledgeBaseName);
StatelessKnowledgeSession session = knowledgeBase.newStatelessKnowledgeSession();
session.setGlobal("countryService", countryService);
session.execute(facts);
}
,并且测试类:
public class TestForeignAddressPostalCode extends BaseTestDomainIntegration
{
private final Collection<Object> postalCodeMinLength0 = new ArrayList<Object>();
@Mock
protected CountryService countryService;
@InjectMocks
private ValidationService level2ValidationService;
@BeforeMethod(alwaysRun=true)
protected void setup()
{
// Get the object under test (here the determination engine)
level2ValidationService = (ValidationService) getAppContext().getBean("validationService");
// and replace the services as documented above.
MockitoAnnotations.initMocks(this);
ForeignAddress foreignAddress = new ForeignAddress();
foreignAddress.setCountryCode("7029");
foreignAddress.setForeignPostalCode("foreign");
// mock country to be able to return a fixed id
Country country = mock(Country.class);
foreignAddress.setLand(country);
doReturn(Integer.valueOf(1)).when(country).getId();
doReturn(country).when(countryService).getCountryById(anyInt());
ContextualAddressBean context = new ContextualAddressBean(foreignAddress, "", AddressContext.CORRESPONDENCE_ADDRESS);
postalCodeMinLength0.add(context);
}
@Test
public void PostalCodeMinLength0_ExpectError()
{
// Execute
level2ValidationService.validateFields(postalCodeMinLength0, null);
}
任何想法做什么,如果我想保持这种@Transactional注释也能够存根countryservice methodes?
问候,
迈克尔
你能更确切地说明你为什么知道mockito失败的原因? 此外,虽然与问题无关,但您应该注意,嘲笑值并不是真正建议的,您应该自己创建一个值实例,也许在测试中使用自定义工厂或私有构造函数等等。 – Brice
也可以显示更多的'BaseTestDomainIntegration',并且如果相关的话可能是spring配置。 – Brice
嗨brice,我已经添加了更多信息。看到子弹 – Michael