I am trying to use Constructor Injection dependency pattern.
I wonder what is the correct approach to inject JPA Repositories on Integration test classes:
I have my source code:
RepoClass
@Repository
public interface MyClassRepo extends JpaRepository<MyClass, Long> {
... methods ...
}
Service following cosntructor injection
public class MyClassService {
private final MyClassRepo myClassRepo;
public DeviceServiceImpl(final MyClassRepo myClassRepo) {
this.myClassRepo = myClassRepo;
}
public boolean myMethodToTest() {
... whatever...
}
}
To test it: (Here comes my issue)
SpringRunner class OPTION 1: Constructor injection
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MyTestConfigClass.class) // With necessary imports
@SpringBootTest
public class MyClassTester {
private final MyClassService myClassService;
private final MyClassRepository myClassRepository;
public MyClassTester (final MyClassRepository deviceRepository) {
this.myClassRepository = myClassRepository;
this.myClassService= new myClassService(myClassRepository);
}
}
Does not work since console output says:
Test class should have exactly one public zero-argument constructor
SpringRunner class OPTION 2: Autowired injection
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MyTestConfigClass.class) // With necessary imports
@SpringBootTest
public class MyClassTester {
@Autowired
private MyClassRepository myClassRepository;
private MyClassService myClassService = new myClassService(myClassRepository);
}
I feel like it is breaking the desired pattern.
SpringRunner class OPTION 3: Empty Constructor
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MyTestConfigClass.class) // With necessary imports
@SpringBootTest
public class MyClassTester {
private final MyClassService myClassService;
private final MyClassRepository myClassRepository;
public MyClassTester () {
this.myClassRepository = new MyClassRepository(); // Obviously NOT working, since its an interface
this.myClassService= new myClassService(myClassRepository);
}
}
As commented: Obviously NOT working, since MyClassRepository its an interface
Is there any better approach to solve this issue?
Use Junit 5. It allows constructors with multiple arguments.
Option 1 would need @Autowired added to the test constructor
From the documentation:
The TestContext framework does not instrument the manner in which a test instance is instantiated. Thus the use of @Autowired or @Inject for constructors has no effect for test classes.
https://docs.spring.io/autorepo/docs/spring-framework/4.2.0.RC2/spring-framework-reference/html/integration-testing.html#testcontext-fixture-di
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With