Reputation: 4255
I'm working on a REST endpoint using Spring and I'd like to test the business logic separately in a way when it includes the mapper, repository and validation logics. They are not mocked. It is a fat integration test (if this definition exists) or a system test but the REST part is not included.
Why not mocking? I don't like them, they don't really provide any value since I define their behavior and that definition does not reflect on the code I want to test. It can be as buggy as the code I wrote. :) For me the value is when I can test the whole stack or big portion of the stack in build time, and fast. I rather manipulate the inputs to trigger behaviors and leave the mocks for behaviors cannot be triggered by inputs (do thsey make any sense?).
The problem I face is how to wire these together in a test? All the examples and articles I have found so far are 1, @DataJpaTest
which focuses only the repository, 2, Controller or system tests with mocked underlying logic.
What I need is the ability to test my small libraries in a the combination (either have them mocked, not mocked or some of them mocked and some of them not) I see valuable.
Based on the articles I read so far the problem is that during testing Spring loads just a slice of the context and I need to load what I need to be there. I haven't found that how can I load into the test context what I need.
public class IAMBusinessLogicImplementation implements IAMBusinessLogicInterface {
private final UserRepositoryInterface _userRepository;
private final UserMapperInterface _userMappers;
private final IAMValidatorInterface _validator;
public IAMBusinessLogicImplementation(
@NonNull UserRepositoryInterface _userRepository,
@NonNull UserMapperInterface _userMappers,
@NonNull IAMValidatorInterface _validator) {
this._userRepository = _userRepository;
this._userMappers = _userMappers;
this._validator = _validator;
}
public UserDto createUser(@NonNull UserDto userDto) {
// stuff
}
}
public class IAMValidatorImplementation implements IAMValidatorInterface { }
public class UserMapperImplementation implements UserMapperInterface { }
public interface UserRepositoryInterface extends CrudRepository<User, Long> { }
Test:
@SpringBootTest(classes = {IAMBusinessLogicImplementation.class})
@EnableJpaRepositories(basePackages = "com.encyclopediagalactica.iam.tests.repository")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@AutoConfigureDataJpa
@EntityScan("com.encyclopediagalactica.iam.entities")
@ComponentScan()
public class IAMBusinessLogicTestsBase {
@Autowired
public IAMBusinessLogicInterface _sut;
@Test
public void createUser() {
// Arrange
UserDto userDto = UserDto.builder()
.firstName("asd")
.lastName("dsa")
.build();
// Act
UserDto result = _sut.createUser(userDto);
// Assert
assertThat(result).isNotNull();
}
}
Result:
2023-04-23T21:28:24.598+02:00 INFO 37577 --- [ main] c.e.i.t.b.IAMBusinessLogicTestsBase : Starting IAMBusinessLogicTestsBase using Java 17.0.7 with PID 37577 (started by andrascsanyi in /Users/andrascsanyi/DEV/github.com/EncyclopediaGalactica/IAM/IAM) 2023-04-23T21:28:24.601+02:00 INFO 37577 --- [ main] c.e.i.t.b.IAMBusinessLogicTestsBase : No active profile set, falling back to 1 default profile: "default" 2023-04-23T21:28:24.739+02:00 INFO 37577 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2023-04-23T21:28:24.759+02:00 INFO 37577 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 JPA repository interfaces. 2023-04-23T21:28:24.899+02:00 INFO 37577 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2023-04-23T21:28:24.919+02:00 INFO 37577 --- [ main] org.hibernate.Version
: HHH000412: Hibernate ORM core version 6.1.7.Final 2023-04-23T21:28:25.049+02:00 INFO 37577 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2023-04-23T21:28:25.137+02:00 INFO 37577 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:testing user=SA 2023-04-23T21:28:25.138+02:00 INFO 37577 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2023-04-23T21:28:25.147+02:00 INFO 37577 --- [
main] SQL dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect 2023-04-23T21:28:25.489+02:00 INFO 37577 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator
: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] 2023-04-23T21:28:25.492+02:00 INFO 37577 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2023-04-23T21:28:25.495+02:00 WARN 37577 --- [ main] o.s.w.c.s.GenericWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'IAMBusinessLogicImplementation': Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.encyclopediagalactica.iam.repositories.UserRepositoryInterface' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} 2023-04-23T21:28:25.495+02:00 INFO 37577 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2023-04-23T21:28:25.495+02:00 INFO 37577 --- [ main] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down' 2023-04-23T21:28:25.497+02:00 INFO 37577 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2023-04-23T21:28:25.498+02:00 INFO 37577 --- [
main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 2023-04-23T21:28:25.500+02:00 INFO 37577 --- [
main] .s.b.a.l.ConditionEvaluationReportLogger :Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2023-04-23T21:28:25.508+02:00 ERROR 37577 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
Upvotes: 0
Views: 773
Reputation: 124934
You are trying to outsmart Spring Boot and its loading mechanisms. Don't do that as you should be working with the framework.
You have 2 options here.
@SpringBootTest
and load the full context (maybe with some mocked services, or in-memory database implementations).@TestConfiguration
to load exactly what you need.I strongly suggest option 1. as option 2 will get quite tedious and will probably lead to longer test times (as there is no reuse of a previously loaded context).
Upvotes: 2