ルールでサービス クラスを使用する drools ルール ファイルがあります。したがって、1 つのルールは次のようになります。
eval(countryService.getCountryById(1) != null)
@service および @Transactional(propagation=Propagation.SUPPORTS) でアノテーションが付けられた検証サービスでは、drools ファイルが statelessKnowledgebase で使用され、drool で使用する必要があるファクトが追加されます。それが完了すると、session.execute(facts) が呼び出され、ルール エンジンが開始します。
ルールをテストするために、countryService.getCountryById() をスタブしたいと思います。mockitoを使用しても大きな問題はありません。drools セットアップを使用する他のサービスに対してもこれを実行すると、正常に機能しました。ただし、この特定のケースでは、countryService がスタブ化されておらず、その理由がわかりませんでした。多くの時間を費やしてコードをチェックした後、 @Transactional をサービスの上に置くか、このアノテーションを欠くことが違いを生むことがわかりました。@Transaction がないため、mockito は問題なく countryservice のモックを作成しました。 @transactional を配置すると、mockito は (エラーやヒントなしで) モックの注入に失敗し、元の countryservice オブジェクトが使用されました。
私の質問は、なぜこの注釈がこの問題を引き起こすのかということです。@Transactional が設定されている場合、mockito がモックを注入できないのはなぜですか? drools セッションにグローバルとして追加されるときに countryService をデバッグおよび検査すると、mockito が失敗することに気付きました。デバッグ ウィンドウで countryService を検査すると、次の違いが見られます。
@transactional を使用: countryService の値は CountryService$$EnhancerByCGLIB$$b80dbb7b です。
@transactional:countryService がない場合、値は CountryService$$EnhancerByMockitoWithCGLIB$$27f34dc1 になります。
さらに @transactional を使用すると、countryservice メソッドの getCountryById のブレークポイントが見つかり、デバッガーはそのブレークポイントで停止しますが、@transactional がないと、mockito がバイパスするため、ブレークポイントはスキップされます。
検証サービス:
@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 メソッドをスタブ化できるようにしたい場合はどうすればよいですか?
よろしく、
マイケル