Мы реализуем часть нашей безопасности на уровне обслуживания, поэтому я добавляю аннотацию @PreAuthorize к некоторым методам MyService.
На MyServiceSecurityTest я хочу протестировать только матрицу безопасности-роль-разрешение, без какой-либо бизнес-логики. По этой причине мне приходится издеваться над MyService. проблема в том, что и Mockito, и Spring используют прокси-серверы CGLIB, а мой сервис не улучшен с помощью @PreAuthorize после Mockito.mock(MyService.class).
Есть ли способ имитировать сервис и сохранить логику @PreAuthorize?
Пример:
@Service
public class MyService implements IMyService {
@Override
@PreAuthorize("hasAuthority('SYSOP')")
public void someMethod(ComplexDTO dto) {
// lots of logic and dependencies, require lots of stubbing.
}
}
Чтобы избежать инициализации всех зависимостей MyService#someMethod и сборки ComplexDTO на MyServiceSecurityTest, я хочу имитировать MyServiceSecurityTest, но сохранить проверки @PreAuthorize.
@cosmos Я не знаком с @MockBean. Я только что заменил @Mock MyService service на @MockBean MyService service и получил тот же результат. Я что-то пропустил? Почему вы думаете, что это поможет?
@cosmos Мне не нужно ничего переопределять. Я хочу опробовать все методы
@cosmos мне нужно поиздеваться и протестировать @PreAuthorize("hasAuthority('SYSOP')") public void someMethod() { ... }
Почему бы вам не поставить под вопрос весь класс, который вы хотите протестировать, и удалить логику, которую вы не хотите показывать публике. Так вам будет легче понять вашу проблему.
@dur нет, насколько я понимаю, аннотация @PreAuthorize не будет работать на уровне интерфейса, и я должен объявить безопасность на уровне реализации и принудительно использовать проксирование CGLIB.
@dur вау! Ты прав, не знал этого. Может я читал устаревшие статьи. Я попробую это сделать в течение следующих нескольких часов. В любом случае, спасибо вам большое!
@dur, даже после перемещения аннотаций на уровень интерфейса, прокси-сервер mockito не имеет проверок безопасности.
@dur MockBean не помог
Вам нужно проводить интеграционные тесты, а не модульные тесты. В общем, вы не видите фиктивные классы в интеграционных тестах, по крайней мере, вы не будете имитировать тестируемый класс, в данном случае я предполагаю, что это класс MyService.
Настройка интеграционных тестов требует дальнейшего чтения, но приведенный ниже короткий пример должен указать вам верный путь.
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("myProfile")
public class MyServiceIT {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testMyService() {
logger.info("testMyService");
//user TestRestTemplate to call your service.
}
}
Обновлено: в этом интеграционном тесте Spring загружается нормально. Это означает, что все аннотации для безопасности обрабатываются, и все bean-компоненты, необходимые для создания, создаются и правильно вводятся. Возможно, вам придется контролировать профиль Spring .... это можно сделать с помощью аннотации @ActiveProfiles("myProfile"), которую я только что добавил в пример.
это вариант, которого я стараюсь избегать. Если я буду тестировать на вашем пути - я должен протестировать и безопасность, и бизнес-логику MyService в одном месте.
Я начинаю думать, что мало кто сталкивался с этой проблемой. И нет навороченного решения. Это может означать, что это неправильный подход - покрыть сервисную безопасность такими тестами.
с другой стороны, предположим, что ваш сервис выполняет действительно тяжелую логику. Выполнение одного метода занимает 10-30 секунд. Теперь у вас около 30 ролей, и вы хотите протестировать каждый метод для каждой роли. На это уйдет довольно много времени.
Можете ли вы замкнуть логику? Я ненавижу встраивать тестовые сценарии в бизнес-логику, но, возможно, если это будет сделано элегантно, это будет не слишком пренебрежительно.
Я просто имею в виду, что при общем интеграционном тесте вы будете тестировать каждую конечную точку, скажем, в нескольких случаях. Если вы собираетесь тестировать безопасность - количество тестовых вызовов будет умножено на количество ролей / полномочий. Но интеграционный тест - вещь довольно тяжелая. Не знаю, чем здесь поможет бизнес-логика (
Раньше мы создавали интерфейс для всех наших классов обслуживания. Затем мы сделали бы для него импл. Что, если вы сделаете то же самое, и у вас может быть имплант, в котором есть только аннотации безопасности, а затем внедрить этот пустой имплант безопасности вашего интерфейса службы?
да, я думал об этом варианте. Но создание отдельного класса для каждой службы только в тестовых целях может оказаться накладными расходами. Я даже не уверен, нужно ли мне так тестировать безопасность
Другой простой способ - просто переопределить метод обслуживания, который вы не хотите тестировать.