How to rollback Rabbit-mq message after Junit test? - junit

When you test your code, you send a message to rabbit-mq. How do you get the message back when the test is over?
public interface RabbitProducer {
String OUTPUT = "rabbitmq_producer_channel";
#Output(OUTPUT)
MessageChannel output();
}
public class SysGroupServiceImpl {
#Autowired
private RabbitProducer rabbitProducer;
#Override
public Result remove(Collection<? extends Serializable> idList) {
rabbitProducer.output().send(MessageBuilder.withPayload(idList)
.setHeader("x-delay", 5000)
.setHeader("MessageType", "GroupBatchDelete").build());
return Result.booleanResult(true);
}
}
#SpringBootTest
#Transactional
#Rollback
public class SysGroupServiceTest {
#Autowired
private SysGroupService sysGroupService;
#Test
void removeTest(){
sysGroupService.remove(Stream.of("1").collect(Collectors.toList()));
}
}
I use Spring Cloud Stream to be compatible with RabbitMQ, and all the relevant code is there.Is there a way to mock this out?I tried the following scheme, but due to X-dealy, I got this error:No exchange type x-delayed-message
<dependency>
<groupId>com.github.fridujo</groupId>
<artifactId>rabbitmq-mock</artifactId>
</dependency>
#Component
public class RabbitMqMock {
#Bean
public ConnectionFactory connectionFactory() {
return new CachingConnectionFactory(MockConnectionFactoryFactory.build());
}
}
I know little about mocks. Can mocks create an X-delay exchange?

Related

autowired ObjectMapper is null during #DataJpaTest

I want to test my implementation for AttributeConverter using #DataJpaTest.
test code
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class FooRepositoryTest {
#Autowired
private FooRepository repository;
#Test
void getPojoTest(){
FooEntity fooEnity= repository.findById("foo");
FooPojo fooPojo = fooEntity.getJsonPojo()
//some assertion
}
}
Entity
#Entity
#Data
#NoArgsConstructor
public class FooEntity{
....
#Column(columnDefinition= "JSON")
#Convert(converter = FooConverter.class)
private FooPojo data;
....
}
Attribute Converter
public class FooConverter implements AttributeConverter<FooPojo, String> {
#Autowired
private ObjectMapper mapper;
#SneakyThrows
#Override
public String convertToDatabaseColumn(FooPojo attribute) {
return mapper.writeValueAsString(attribute);
}
#SneakyThrows
#Override
public FooPojo convertToEntityAttribute(String dbData) {
return mapper.readValue(dbData, FooPojo.class);
}
}
with my code above, when I run getPojoTest(), the #autowired OjbectMapper in Converter is null. When I try the same test with #SpringBootTest instead, it works just fine. I wonder is there any walk-around to use #DataJpaTest and ObjectMapper together.
A better alternative compared to creating your own ObjectMapper is adding the #AutoConfigureJson annotation:
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#AutoConfigureJson
public void FooRepositoryTest {
}
This is also what #JsonTest uses.
From Docs:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.

how to mock restTemplate getForObject

I want to test the restTemplate.getForObject method using a mock but having issues. I'm new with Mockito, so I read some blogs about testing restTemplate using Mockito but still can not write a successful test.
The class to test is :
package rest;
#PropertySource("classpath:application.properties")
#Service
public class RestClient {
private String user;
// from application properties
private String password;
private RestTemplate restTemplate;
public Client getClient(final short cd) {
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(user, password));
Client client = null;
try {
client = restTemplate.getForObject("http://localhost:8080/clients/findClient?cd={cd}",
Client.class, cd);
} catch (RestClientException e) {
println(e);
}
return client;
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
}
My test class :
package test;
#PropertySource("classpath:application.properties")
#RunWith(MockitoJUnitRunner.class)
public class BatchRestClientTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private RestClient restClient;
private MockRestServiceServer mockServer;
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void getCraProcessTest() {
Client client=new Client();
client.setId((long) 1);
client.setCd((short) 2);
client.setName("aaa");
Mockito
.when(restTemplate.getForObject("http://localhost:8080/clients/findClient?cd={cd},
Client.class, 2))
.thenReturn(client);
Client client2= restClient.getClient((short)2);
assertEquals(client, client2);
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public RestClient getRestClient() {
return restClient;
}
public void setRestClient(RestClient restClient) {
this.restClient = restClient;
}
}
It is returning null and not the expected client, the restTemplate for Object class works fine. I want just to write the test . Am I missing something or doing the test wrong way?
Thanks for any guidance.
Use this instead:
Mockito.when(restTemplate.getForObject(
"http://localhost:8080/clients/findClient?cd={id}",
Client.class,
new Object[] {(short)2})
).thenReturn(client);
The third parameter is a varargs.
So you need to wrap into an Object[] in the test, otherwise Mockito is not able to match it. Note that this happens automatically in your implementation.
Also:
You forgot to terminate your url (missing closing ") in your examples in the question. Probably just a typo.
You used different url's in your implementation in your test: ...?cd={cd} instead of ...?cd={id}.(As previously pointed out by #ArnaudClaudel in the comments).
You did not define a behaviour for restTemplate.getInterceptors() so I would expect it to fail with a NullPointerException, when trying to add the BasicAuthenticationInterceptor.
Additionally you might want to check my answer here for another example of how to mock the getForObject method. Note that it does not include a case where any of the real parameters would be null.

Mocking an injected object in a method return and UnsupportedOperationException method

I have a class that returns an injected object using Mockito. Everytime I test it, it returns a bull. How would I properly test it to return the correct object?
My class to test:
#Component
public class CarImpl {
#Inject
private Engine v6EngineImpl;
public Engine getEngine() {
return v6EngineImpl;
}
public Exhaust getExhaust() {
throw new UnsupportedOperationException("unsupported");
}
}
Tests:
#RunWith(MockitoJUnitRunner.class)
public class CarTest {
#InjectMocks
private CarImpl carImpl;
#Mock
private Engine v6EngineImpl;
#Test
public void testGetEngine(){
Engine v6EngineImpl = mock(V6EngineImpl.class);
Engine engine = carImpl.getEngine();
// always returns a bull no matter what, how to mock inject.
//return object correctly?
Assert.assertNotNull(engine);
}
#Test
public void testGetExhaust() {
// how to test thrown exception?
}
}
Thanks, I am not too familiar thanks
Try this:
#RunWith(MockitoJUnitRunner.class)
public class CarTest {
#InjectMocks
private CarImpl carImpl;
#Mock
private Engine v6EngineImpl;
#Test
public void testGetEngine(){
Engine engine = carImpl.getEngine();
//engine is the mock injected to CarImpl
Assert.assertNotNull(engine);
Assert.assertSame(engine,v6EngineImpl);
}
#Test(expected=UnsupportedOperationException.class)
public void testGetExhaust() {
carImpl.getExhaust();
}
}

How to write JUnit Test case

I am learning Junit testing on spring boot Application. my account controller method is depend on service class method. For that I used Mockito. I tried simple But here I am not getting how to write test case for following method? How I can use mockito.
can any one please help me for writing this test case?
AccountController
#RestController
#RequestMapping("/spacestudy/$ {InstituteIdentifier}/admin/account")
public class AccountController {
#Autowired
AccountService accService;
#GetMapping("/findAccountData")
public ResponseEntity<List<Tuple>> populateGridViews(#RequestParam(value="sClientAcctId",required=false) String sClientAcctId,
#RequestParam(value="sAcctDesc",required=false) String sAcctDesc,
#RequestParam(value="sInvestigatorName",required=false)String sInvestigatorName,
#RequestParam(value="sClientDeptId",required=false) String sClientDeptId) throws Exception {
return ResponseEntity.ok(accService.populateGridViews(sClientAcctId, sAcctDesc,sInvestigatorName,sClientDeptId));
}
}
AccountService
public List<Tuple> populateGridViews(String sClientAcctId, String sAcctDesc, String sInvestigatorName,
String sClientDeptId)throws Exception{
QAccount account = QAccount.account;
QDepartment department = QDepartment.department;
QAccountCPCMapping accountCPCMapping = QAccountCPCMapping.accountCPCMapping;
QInvestigator investigator = QInvestigator.investigator;
JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
query.select(Projections.bean(Account.class, account.sClientAcctId, account.sAcctDesc, account.sLocation,
Projections.bean(Department.class, department.sDeptName, department.sClientDeptId).as("department"),
Projections.bean(Investigator.class, investigator.sInvestigatorName).as("investigator"),
Projections.bean(AccountCPCMapping.class, accountCPCMapping.sCCPCode).as("accountCPC"))).from(account)
.innerJoin(account.department, department).innerJoin(account.accountCPC, accountCPCMapping)
.innerJoin(account.investigator, investigator);
if (StringUtils.isNotEmpty(sClientAcctId)) {
query.where(account.sClientAcctId.equalsIgnoreCase(sClientAcctId));
}
// code.......
return query.fetch();
}
AccountControllerTest
#RunWith(SpringRunner.class)
public class TestAccountController {
private MockMvc mockMvc;
#Mock
private AccountService accountService;
#InjectMocks
private AccountController accountController;
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(accountController).build();
}
#Test
public void populateGridViewsTest() throws Exception {
//????
//????
}
}
It will be something like this:
#RunWith(SpringRunner.class)
public class TestAccountController {
private MockMvc mockMvc;
#Mock
private AccountService accountService;
#InjectMocks
private AccountController accountController;
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(accountController).build();
}
#Test
public void populateGridViewsTest() throws Exception {
when(accountService.populateGridViews("foo","bar")).thenReturn(Arrays.asList(new Tuple("bazz"));
mockMvc.perform(get("/spacestudy/STACKOVERFLOW/admin/account/foo/bar"))
.andExpect(status().isOk())
.andExpect(jsonPath("someField").value("bazz"));
}
}
So basically you are replacing your service with mock and saying what it should return. In your particular case I don't see any reasons for unit testing this class, since it doesn't have any logic inside. But if you would have something like:
#GetMapping("/findAccountData")
public ResponseEntity<List<Tuple>> populateGridViews(...) throws Exception {
List<Tuple> result = accService.populateGridViews(...);
if(result==null){
return ResponseEntity.notFound();
}
return ResponseEntity.ok(result);
}
Then it would make more sense to test this class e.g.
1st test - mock your accService to return null and verify that response status is 404
2nd test - mock your accService to return not null and verify that response status is 200

Using HttpMessageConverter causes HTTP 406

After extensive investigations, I wanted to share the problem and the resolution.
Problem
I have a RestController that works well, as long as I'm in charge of converting the JSON message. The moment I try to use an HttpMessageConverter to make the conversion more elegant, the client will start receiving HTTP 406.
So this works:
#RequestMapping(value = "/objects", method = RequestMethod.GET)
public Map<String, Object>[] getObjects(#RequestBody Object jsonQuery) {
MyQuery query = new MyConverter().convert(jsonQuery);
// do something with query
}
But, when I configure the converter, like this:
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
httpMessageConverters.add(new QueryMessageConverter(new MediaType("application", "json")));
}
}
This causes HTTP 406:
#RequestMapping(value = "/objects", method = RequestMethod.GET)
public Map<String, Object>[] getObjects(#RequestBody Query Query) {
// do something with query
}
My pom.xml only refers spring-boot, and doesn't mention jackson at all.
Solution
See below
The solution is really very simple, and it is to register the jackson handler explicitly:
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
httpMessageConverters.add(new QueryMessageConverter(new MediaType("application", "json")));
httpMessageConverters.add(new MappingJackson2HttpMessageConverter());
}
}