У меня есть файл правил слюни, который использует классы обслуживания в правилах. Итак, одно правило делает что-то вроде этого:
eval (countryService.getCountryById (1)! = null)
В сервисе проверки, который аннотируется @service и @Transactional (ropagation = Propagation.SUPPORTS), файл слюни используется в базе знаний без сохранения состояния, и добавляются факты, которые следует использовать в слюне. После этого вызывается session.execute (факты) и запускается механизм правил.
Чтобы проверить правила, я хотел бы заглушить countryService.getCountryById (). Нет большой проблемы с использованием mockito. Сделано это для другой службы, которая также использует настройку слюни, и она работала нормально. Однако в этом конкретном случае countryService не был заглушен, и я не мог понять, почему. Потратив много времени и проверив свой код, я обнаружил, что наличие @Transactional над сервисом или отсутствие этой аннотации имеет значение. Отсутствие @Transaction заставило mockito имитировать countryservice без каких-либо проблем, наличие @transactional на месте привело к сбою mockito (без каких-либо ошибок или подсказок), вводящего макет, поэтому использовался исходный объект countryservice.
У меня вопрос, почему эта аннотация вызывает эту проблему. Почему mockito не может вводить макеты, если установлен @Transactional? Я заметил, что mockito не работает, так как когда я отлаживаю и проверяю countryService, когда он добавляется как глобальный в сеанс слюни, я вижу следующую разницу, когда проверяю countryservice в моем окне отладки:
с @transactional: countryService имеет значение CountryService $$ EnhancerByCGLIB $$ b80dbb7b
без @transactional: countryService имеет значение CountryService $$ EnhancerByMockitoWithCGLIB $$ 27f34dc1
Вдобавок с @transactional моя точка останова в методе 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, но при этом иметь возможность заглушить методы обслуживания страны?
С уважением,
Майкл
BaseTestDomainIntegration
и, возможно, конфигурацию пружины, если это актуально. - person Brice   schedule 12.10.2012CountryService
bean? В таком случае вы можете вместо этого создать макет в контексте Spring. Я считаю, что комбинация базового класса Spring / some aspect / testng может вызвать некоторое дополнительное поведение после создания макета, который в вашем случае я Подозреваемый - это замена mockito mock. - person Brice   schedule 12.10.2012CountryService
в контексте spring , если его еще нет (как вы только что сказали). Другой вариант - выполнить код вашего метода before в самом методе тестирования. Также обратите внимание, что@InjectMocks
, которая является аннотацией mockito, даже не заботится об аннотации@Autowired
Spring, она ищет только тип и имя поля. - person Brice   schedule 12.10.2012