How to set and inject property Value from Test in Junit - spring

My Service class uses a property set it application.properties
#Service
public class Service {
#Value("${my.prop}")
private String prop;
public Response doWork(String param1,String param2){
System.out.println(prop); //NULL!!!
}
}
I want to test it and set my own value:
Test Class:
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource(locations = "application.properties",properties = { "my.prop=boo" })
public class ServiceUnitTest {
#InjectMocks
private Service service;
#Test
public void fooTest(){
Response re = service.doWork("boo", "foo");
}
}
But when I run the test, the value is null (not even the value that exists in application.properties).

I don't have experience with MockitoJUnitRunner, but I am able to achieve this using PowerMockRunner.
Set up the application context with a test configuration, and autowire the bean from you application context into your test class. You also shouldn't need the "locations = " bit in the #TestPropertySource annotation.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
#TestPropertySource(properties = { "my.prop=boo" })
public class ServiceUnitTest {
#TestConfiguration
static class ServiceUnitTestConfig {
#Bean
public Service service() {
return new Service();
}
}
#Autowired
Service service;
#Test
public void fooTest(){
Response re = service.doWork("boo", "foo");
}
}

Related

Verifying pointcuts being called in tests

I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}

Mocking a service in a Testcontainer Spring boot test

I am quite new in Spring and I am facing an issue right now with testing:
I have the following Service:
#Service
public class MyService {
public Integer getKey() {
List<Integer> keys = getKeys(1);
if (keys.size() == 1) {
return keys.get(0);
}
throw new IllegalArgumentException("Error!");
}
... and a getKeys() method, which provides a list based ona rest call...
}
And I use this service class in antother class:
#NoArgsConstructor
public class MyOtherClass extends MyClass {
#Autowired
private MyService myService;
....
#Override public KeyValue<Object, Object> doSomething(Object key, Object value) {
if (conditionIsTrue(key, value)) {
MyObject obj = new MyObject();
myObject.setKey(keyService.getKey()); ----- here is always null the keyService
.....
} else {
return KeyValue.pair(null, null);
}
}
And I try to write a test but the MyService is always null..
#ActiveProfiles("my-test")
#SpringBootTest(classes = Application.class)
#Testcontainers
#Slf4j
public class MyTest extends TestContext {
#BeforeEach
void init(final TestInfo testInfo) {
....
}
#AfterEach
void deinit() {
....
}
#Test
public void myTest() {
....
}
How can I inject a mock MyService into the test container?
Thank you!

Why did #TestConfiguration not create a bean for my test?

My service
#Service
public class StripeServiceImpl implements StripeService {
#Override
public int getCustomerId() {
return 2;
}
}
My test
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}
The error: java.lang.NullPointerException. I had checked and the stripeService is actually null.
Since you are autowiring you need an applicationcontext so that Spring can manage the bean and then can get injected in your class. Therefore you are missing an annotation to create the applicationcontext for your testclass.
I have updated your code and it works now(with junit 5 on your classpath). In the case dat you are using junit 4 it should be #RunWith(SpringRunner.class) instead of #ExtendWith(SpringExtension.class):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfiguration.class)
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}

Spring boot repository.save() does not work in test class

I have this test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { CrimeServiceDBImpl.class, CrimeController.class, Crime.class })
#ComponentScan("com.springmiddleware")
#EntityScan(basePackages = {"com.springmiddleware.entities"})
#DataJpaTest
#AutoConfigureTestDatabase(replace = Replace.NONE)
#EnableJpaRepositories("com.springmiddleware")
public class TestCrimeServiceDB {
#Autowired
private CrimeServiceDBImpl service = new CrimeServiceDBImpl();
#Test
public void getAll() {
try {
List<Crime> list = this.service.getAllCrimes();
assertTrue(list.size()!=0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The method getAllCrimes() from the service class does just this:
#Service
public class CrimeServiceDBImpl implements CrimeService{
#Autowired
private CrimeRepository repository;
private List<Crime> list = new ArrayList<Crime>();
public CrimeServiceDBImpl() {
list = UtilityMethods.readFromCSV();
};
#Override
public List<Crime> getAllCrimes() throws IOException {
repository.saveAll(list);
return this.repository.findAll();
}
If I call this method when running the application, it correctly add all my objects to the database, but when it's called from the test it doesn't add anything, but no exception is thrown.
Which database are you using? Do you mean the data is not persisted in the database after the test has finished? That's because a test always perform a rollback/cleanup when it has finished its work.

Spring injection: #MockBean #Repository is not injected

I'm trying to #MockBean a #Repository annotated class:
#Repository
public interface ApplicationDao extends MongoRepository<Application, String> {}
I'm injecting it into a #Service annotated class:
#Service
public class AuthorizationService {
private ApplicationDao appsDao;
private List<Application> allowedApplications;
#Autowired
public AuthorizationService(ApplicationDao appsDao) {
this.appsDao = appsDao; //<<MOCKED INJECTED BEAN>>
this.fillApplications();
}
private void fillApplications() {
this.appsDao.findAll() //<<MOCKED method>>
.forEach(entry -> {
this.allowedApplications.put(entry.getName(), entry);
});
}
public bool isAuthorized(Application application) {
return this.allowedApplications
.stream()
.anyMatch(app -> app.getId().equals(application.getId()));
}
}
My test mocking configuration looks like:
#RunWith(SpringRunner.class)
#SpringBootTest()
public class GroupReferencesTest {
private #Autowired AuthorizationService;
private #MockBean ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app)); //<<FAILS>>
}
}
Nevertheless, my mocked object is not injected. I mean, when my AuthorizationService calls its injected ApplicationDao is returns an empty list instead of my mocked list.
I've tried to use #MockBean(name="applicationDao") as well. The behavior is the same.
I've also tried to configure my mocked bean using this code:
#TestConfiguration
public class RestTemplateTestConfiguration {
#Bean("applicationDao")
#Primary
public static ApplicationDao mockApplicationDao() {
ApplicationDao mock = Mockito.mock(ApplicationDao.class);
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(mock.findAll())
.thenReturn(allowedApplications);
return mock;
}
}
However, it doesn't works right.
Application class is:
public class Application {
private String id;
//setters & getters
}
Any ideas?
First things first - the type of test. Answer: Unit test.
You are starting Spring context that manages a lifecycle of AuthorizationService and then you are trying to inject mock. What really happens is that Spring IoC container is injecting a real ApplicationDao (the one managed by Spring IoC container) into the AuthorizationService.
Solution:
Manage lifecyle of AuthorizationService by your test runner (like MockitoJUnitRunner and inject ApplicationDao mock into it):
#RunWith(MockitoJUnitRunner.class)
public class GroupReferencesTest {
private #InjectMocks AuthorizationService authorizationService;
private #Mock ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app));
}
}
Working example
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {AuthorizationService.class})
public class GroupReferencesTest {
#Autowired
private AuthorizationService;
#MockBean
private ApplicationDao applicationDao;
#Test
public void test() {
//given
Mockito.when(applicationDao.findAll()).thenReturn(emptyList());
//when & then
assertTrue(authorizationService.isAuthorized(app));
}
}

Resources