Tengo un archivo de reglas drools que usa clases de servicio en las reglas. Así que una regla hace algo como esto:La anotación transaccional evita que se burlen de los servicios
eval (countryService.getCountryById (1)! = Null)
En un validationservice que se anota con @Service y @Transactional (= propagación Propagation.SUPPORTS) el archivo drools se usa en una base de conocimiento sin estado y se agregan hechos que deberían usarse en la baba. Una vez hecho esto, se invoca session.execute (facts) y se inicia el motor de reglas.
Para probar las reglas, me gustaría incluir el countryService.getCountryById(). No es un gran problema usar mockito. Hecho esto para otro servicio que también usa una configuración de drools y funcionó bien. Sin embargo, en este caso particular, countryService no fue interceptado y no pude entender por qué. Después de pasar mucho tiempo y consultar mi código, descubrí que tener @Transactional por encima del servicio o carecer de esta anotación marcaba la diferencia. Al carecer de @Transaction hizo que el mockito se burlara del servicio del país sin ningún problema, tener el @transactional en su lugar causó que el mockito fallara (sin ningún error o sugerencia) inyectando el simulacro para que se usara el objeto de servicio del país original.
Mi pregunta es por qué esta anotación causa este problema. ¿Por qué no se puede mockito inyectar los simulacros cuando se establece @Transactional? Me he dado cuenta de que Mockito está fallando como cuando puedo depurar e inspeccionar el countryService cuando está siendo añadido como global para la sesión drools veo la siguiente diferencia cuando inspeccione el countryservice en mi DebugWindow:
con @ transaccional: countryService tiene el valor CountryService $$ EnhancerByCGLIB $$ b80dbb7b
sin @Transactional: countryService tiene el valor CountryService $$ EnhancerByMockitoWithCGLIB $$ 27f34dc1
Además con @t mi punto de ruptura se establece en el metodo countryservice getCountryById y el depurador se detiene en ese punto de interrupción, pero sin @transactional mi punto de interrupción se omite ya que mockito lo puentea.
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);
}
Y la clase de prueba:
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);
}
Alguna idea de qué hacer si quiero mantener esta anotación @Transactional sino también ser capaz de derivadas La methodes countryservice?
cordiales,
Michael
Podría ser más ¿Preciso cómo sabes por qué Mockito está fallando? Además, aunque no esté relacionado con el problema, debe tener en cuenta que no se recomienda el valor de burla, en su lugar debe crear una instancia de valor, tal vez con una fábrica personalizada en su prueba o un constructor privado, etc. – Brice
También podría mostrar un poco más de 'BaseTestDomainIntegration' y tal vez la configuración de Spring si eso es relevante. – Brice
Hola, brice, he agregado más información. mira las viñetas – Michael