I have an aspect class as below -
public class TestAspect {
#AfterThrowing(pointcut = "execution(* *(..)) ", throwing = "testException")
public void afterThrowAdvice(TestException testException) throws Exception {
}
}
Now anytime any class throws TestException, TestAspect's afterThrowAdvice method is getting called. From Unit tests as well without using any spring configuration xmls, running as a plain junit test. How do I mock to not do anything when that method is called? I tried in my unit test the below but it won't work. Rightly so because the aspect is not autowired into the classes I am testing. Any suggestions? -
#Mock
private TestAspect testAspect
doNothing.when(testAspect).afterThrowAdvice(any(TestException.class));
One way to achieve this is using #Profile option .
Following profile configuration will make sure the aspect bean is only available with the profile is not test
#Component
#Aspect
#Profile("!test")
public class TestAspect {
#AfterThrowing(pointcut = "execution(* *(..)) ", throwing = "testException")
public void afterThrowAdvice(TestException testException) throws Exception {
...
}
}
and following Junit testcase runs the the tests with profile as test and no aspect bean is created here
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestExConfig.class)
#ActiveProfiles("test")
public class TestService{
#Autowired
ServiceWithException service;
#Test(expected = TestException.class)
public void testExceptionMethod() throws TestException {
service.testMethod();
}
}
Hope this helps
Related
I created an Embedded Sftp server bean for my integration tests, i hooked the startup and the shutdown of the server respectively with the afterPropertiesSet and destroy life cycles
public class EmbeddedSftpServer implements InitializingBean, DisposableBean {
//other class content
#Override
public void afterPropertiesSet() throws Exception {
//Code for starting server here
}
#Override
public void destroy() throws Exception {
//Code for stopping server here
}
}
here my config class
#TestConfiguration
public class SftpTestConfig {
#Bean
public EmbeddedSftpServer embeddedSftpServer() {
return new EmbeddedSftpServer();
}
//Other bean definitions
}
Now when i inject the bean in my test classes like the following :
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = SftpTestConfig .class)
class ExampleOneIT {
#Autowired
private EmbeddedSftpServer embeddedSftpServer;
}
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = SftpTestConfig .class)
class ExampleTwoIT {
#Autowired
private EmbeddedSftpServer embeddedSftpServer;
}
#SpringBatchTest
#ContextConfiguration(classes = SftpTestConfig .class)
class ExampleThreeIT {
#Autowired
private EmbeddedSftpServer embeddedSftpServer;
}
And i run all the test classes simultaneously, i found out that for the test classes annotated with #ExtendWith(SpringExtension.class), it's the same context that is used (which is understandable since i guess spring cache it) and therefore the bean lifecycle methods are not executed again, but to my surprise, for the class annotated with #SpringBatchTest i noticed that the life cycle hooks of the bean are executed again! Which is a behavior that is not convenient since i want the application context to start the server one time for all tests and close it at the end of those tests (which is the case if i use only #ExtendWith(SpringExtension.class) for all my test classes).
N.B. : I need to use #SpringBachTest for my ExampleThreeIT test class.
I think you are hitting this issue: https://github.com/spring-projects/spring-batch/issues/3940 which has been fixed in v4.3.4/4.2.8. Upgrading to one of these versions should fix your issue.
I have a bit of a confusing error in my test scenario.
We want to refactor an Application that is not tested at all. To ensure that we have the same outcame after refactoring I'll write some integration tests for one Controller class.
#RestController
#RequestMapping("/rfq")
public class RfqController {
#Autowired
private RfqRepository rfqRepo;
#Autowired
private RfqDao rfqDao;
...
#PostMapping("/get")
public #ResponseBody BuyerRfqView getRFQ(#RequestBody SingleIdBody body) {
int id = body.getId();
Optional<Rfq> rfq = rfqRepo.getById(id);
...
}
}
In that case I want to test with testcontainers and spring-boot-test everything worked well, containers are up and running and the application starts so far. But the problem is that at runtime the spring-boot-test doesn't Autowire rfqRepo in the class under test. In the Testclass, every single dependency is in the ComponentScan or EntityScan and the repositories are also injected. I have no clue why this is not working. when the test is running I get a Nullpointer Exception by rfqRepo ...
here is the Test class:
#SpringBootTest(classes = RfqController.class, webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
#ComponentScan({...})
#EnableJpaRepositories({...})
#EntityScan({...})
#EnableAutoConfiguration
#ActiveProfiles("local")
#Testcontainers
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class RfqControllerTest {
#Container
private static OracleContainer database = new OracleContainer(
"oracleinanutshell/oracle-xe-11g:latest")
.withExposedPorts(1521, 5500)
.withPassword("...");
#InjectMocks
RfqController rfqController;
#DynamicPropertySource
static void databaseProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", database::getJdbcUrl);
registry.add("spring.datasource.username", database::getUsername);
registry.add("spring.datasource.password", database::getPassword);
}
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
ScriptUtils.runInitScript(new JdbcDatabaseDelegate(database, ""), "ddl.sql");
}
#Test
void testGetRFQ() {
BuyerRfqView result = rfqController.getRFQ(new SingleIdBody(176501));
Assertions.assertEquals(new BuyerRfqView(), result);
}
}
In the SpringBootTest annotation you are only using RfqController. That's the only class then that is available during test.
#SpringBootTest(classes = RfqController.class, webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)
So you have to add all classes that are needed for your tests.
I have a class like this
public abstract class JobProcessor {
#Autowired
ApplicationContext applicationContext;
protected void startProcess() {
MyThread myThread= (MyThread) applicationContext.getBean("myThread");
myThread.setConversionObject(new MyObject());
...
}
}
I want to write unit test for JobProcessor. JobProcessor is an abstract class.and it is autowired with ApplicationContext which is an interface.
My test is like this
#SpringBootTest(classes = JobProcessorApplication.class)
#ContextConfiguration(locations = "classpath:InjectionContext.xml")
#TestPropertySource(locations = "classpath:test.properties")
#Import(UnitTestConfiguration)
class JobProcessorSpec extends Specification {
class JobProcessorChild extends JobProcessor {
#Override
boolean processRequest() {
return false
}
def "Should start process"() {
given:
def jobProcessorChild = new JobProcessorChild()
when:
jobProcessorChild.startProcess()
then:
noExceptionThrown()
}
}
}
My test always fails for nullpoint error of applicationContext
Can anyone please guide me how to write unit test properly here?
Unit tests should run without applicationContext being built. You have to replace it with a mock object which you will then pass into your object's constructor in the test.
#RunWith(SpringRunner.class)
#WebAppConfiguration
Class Test{
#Autowired
public SomeBean someBean;
#Test
public void testAccountPage2() throws Exception {
SomeBean someBean = mock(SomeBean.class);
given(someBean.getAccount(anyString())).willReturn(getCustomer());
}
Here someBean.getAccount(anyString()) is not mocking, which is calling the actual method of that bean impl. It seems it's taking the Autowired object not the mocked one.
Could anyone help me to mock beans in method level? those beans are also autowired in the same class or superclass.
Thanks
To replace a bean in the Spring container by a Mockito mock, use #MockBean.
import org.springframework.boot.test.mock.mockito.MockBean; // import to add
#RunWith(SpringRunner.class)
#WebAppConfiguration
Class Test{
#MockBean
public SomeBean someBean;
#Test
public void testAccountPage2() throws Exception {
given(someBean.getAccount(anyString())).willReturn(getCustomer());
}
}
To understand the difference between Mockito and MockBean from Spring Boot, you can refer to this question.
You need to inject the mock in order to have it working instead of autowiring
//if you are just testing bean/services normally you do not need the whole application context
#RunWith(MockitoJUnitRunner.class)
public class UnitTestExample {
#InjectMocks
private SomeBean someBean = new SomeBean();
#Test
public void sampleTest() throws Exception {
//GIVEN
given(
someBean.getAccount(
//you should add the proper expected parameter
any()
)).willReturn(
//you should add the proper answer, let's assume it is an Account class
new Customer()
);
//DO
//TODO invoke the service/method that use the getAccount of SomeBean
Account result = someBean.getAccount("");
//VERIFY
assertThat(result).isNotNull();
//...add your meaningful checks
}
}
Using Spring boot starter test for testing my application but I am using third party library. Lets suppose we have a class TRequest and it has some constructor and I want to mock and stub that constructor to return the result.
#SpringBootTest
#RunWith(SpringRunner.class)
#PrepareForEverythingForTest
public class TestClass {
#MockBean
TRequest trequest ;
#Before
public void setUp() throws Exception {
PowerMockito.whenNew(TRequest.class).withAnyArguments().thenReturn(trequest);
}
}
Now when I am trying to create the constructor using new, it is not returning the correct stubbed result.
TRequest trequest1 = new TRequest("apiKey","secretKey") ;
trequest.equals(trequest1) ; // false but I want it to be true
Have used a jackson third party lib to test with. - getting ClassLoader exceptions because of PowerMock though.
#SpringBootTest
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
public class TestPowerMockito {
#MockBean
ObjectMapper object;
#Before
public void init() throws Exception {
PowerMockito.whenNew(ObjectMapper.class).withAnyArguments().thenReturn(object);
}
#Test
public void test() {
assertEquals(object, new ObjectMapper());
}
}