Вам не понадобится Spring, чтобы это проверить. Если вы следуете лучшим практикам Spring, когда дело доходит до зависимостей автоматического подключения, вы должны иметь возможность просто создавать объекты самостоятельно и передавать UserRepository
в UserService
Лучшие практики:
- Внедрение конструктора для требуемых bean-компонентов
- Внедрение установщика для необязательных bean-компонентов
- Внедрение поля никогда, кроме случаев, когда вы не можете внедрить конструктор или установщик, что очень и очень редко.
Обратите внимание, что InjectMocks
не является фреймворком для внедрения зависимостей, и я не рекомендую его использовать. Вы можете увидеть в javado c, что он может стать довольно сложным, когда дело доходит до конструктора против установщика против поля.
Обратите внимание, что здесь можно найти рабочие примеры кода в этом репозитории GitHub.
Простой способ очистить ваш код и сделать его более легким для тестирования - это исправить UserService
, чтобы вы могли пройти любую реализацию UserRepository
вы хотите, это также позволяет вам гарантировать неизменяемость,
public class UserService {
public UserService(final UserRepository userRepository) {
this.userRepository = userRepository;
}
public final UserRepository userRepository;
public User newUser(String name, String food) {
var user = new User();
user.setName(name);
user.setFood(food);
return userRepository.save(user);
}
}
, и тогда ваш тест станет более простым,
class UserServiceTest {
private UserService userService;
private UserRepository userRepository;
private static User savedUser;
@BeforeEach
void setup() {
userRepository = createMockRepo();
userService = new UserService(userRepository);
}
@Test
void testSaveUser(){
String name = "Steve";
String food = "Apple";
userService.newUser(name, food);
assertEquals(savedUser.getName(), name);
assertEquals(savedUser.getFood(), food);
}
public UserRepository createMockRepo() {
UserRepository mockRepo = mock(UserRepository.class);
try {
doAnswer(
(Answer<Void>) invocation -> {
savedUser = (User) invocation.getArguments()[0];
return null;
})
.when(mockRepo)
.save(any(User.class));
} catch (Exception e) {
}
return mockRepo;
}
}
Однако это не добавляет На мой взгляд, большая выгода, поскольку вы взаимодействуете с репозиторием непосредственно в сервисе, если вы не полностью понимаете сложность репозитория данных Spring, в конце концов, вы также издеваетесь над сетевым вводом-выводом, что является опасной вещью
- Как работают аннотации @Id?
- А как насчет Hibernate JPA взаимодействует с моим Entitiy?
- Соответствуют ли определения столбцов в моем Entitiy тому, что я бы сделал eploy против при использовании чего-то вроде Liquibase / Flyway для управления миграциями базы данных?
- Как проверить наличие любых ограничений, которые может иметь база данных?
- Как проверить настраиваемые границы транзакций?
Вы запекаете множество предположений, для этого вы можете использовать аннотацию @ DataJpaTest документации, которую предоставляет Spring Boot, или реплицировать конфигурацию. На этом этапе я предполагаю, что это приложение Spring Boot, но та же концепция применима к приложениям Spring Framework, вам просто нужно настроить конфигурации et c.
@DataJpaTest
class BetterUserServiceTest {
private UserService userService;
@BeforeEach
void setup(@Autowired UserRepository userRepository) {
userService = new UserService(userRepository);
}
@Test
void saveUser() {
String name = "Steve";
String food = "Apple";
User savedUser = userService.newUser(name, food);
assertEquals(savedUser.getName(), name);
assertEquals(savedUser.getFood(), food);
}
}
В этом примере мы пошли дальше и удалили любое понятие имитации, подключаемся к базе данных в памяти и проверяем, что возвращенный пользователь не изменился на то, что мы сохранили .
Тем не менее, существуют ограничения для баз данных в памяти для тестирования, поскольку мы обычно развертываем что-то вроде MySQL, DB2, Postgres et c. где определения столбцов (например) не могут быть точно воссозданы базой данных в памяти для каждой «реальной» базы данных.
Мы могли бы пойти дальше и использовать Testcontainers, чтобы развернуть docker изображение база данных, к которой мы будем подключаться во время выполнения и подключаться к ней в рамках теста
@DataJpaTest
@Testcontainers(disabledWithoutDocker = true)
class BestUserServiceTest {
private UserService userService;
@BeforeEach
void setup(@Autowired UserRepository userRepository) {
userService = new UserService(userRepository);
}
@Container private static final MySQLContainer<?> MY_SQL_CONTAINER = new MySQLContainer<>();
@DynamicPropertySource
static void setMySqlProperties(DynamicPropertyRegistry properties) {
properties.add("spring.datasource.username", MY_SQL_CONTAINER::getUsername);
properties.add("spring.datasource.password", MY_SQL_CONTAINER::getPassword);
properties.add("spring.datasource.url", MY_SQL_CONTAINER::getJdbcUrl);
}
@Test
void saveUser() {
String name = "Steve";
String food = "Apple";
User savedUser = userService.newUser(name, food);
assertEquals(savedUser.getName(), name);
assertEquals(savedUser.getFood(), food);
}
}
Теперь мы точно тестируем, можем ли мы сохранить и сопоставить нашего пользователя с реальной базой данных MySQL. Если мы сделаем еще один шаг и добавим журналы изменений и т. Д. c. они также могут быть зафиксированы в этих тестах.