My application is running in local, I am trying to do Spring Rest Controller testing.
It is running in 8089 port.
In application.yml
spring:
profiles:
active: sit
In application-sit.yml
server:
port: 8089
servlet:
context-path: /myapp
In My base test case:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MyApplication.class)
#WebAppConfiguration
public abstract class AbstractTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
#Value("${server.port}")
int serverPort;
/* #LocalManagementPort
int randomManagementPort;*/
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected String mapToJson(Object obj) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
}
My Controller Test class:
public class OtpControllerTest extends AbstractTest {
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void sendOtpTest() throws Exception {
String uri = "/sendOtp";
SendOTPRequestDTO otpRequest = new SendOTPRequestDTO();
otpRequest.setClientId("default2");
otpRequest.setTag("tag");
otpRequest.setMobileNumber("4444888888");
String inputJson = super.mapToJson(otpRequest);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
//.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
String content = mvcResult.getResponse().getContentAsString();
assertEquals(8089,serverPort);
assertEquals(200, status);
}
}
I am getting output like this:
java.lang.AssertionError: expected:<8089> but was:<-1>
I gone through the all similar issues and tried even no result.
I am fallowing this source:
test.htmSpring Boot - Rest Controller Unit Test
Related
i added a mocked user this my class
#TestConfiguration
public class UserDetailsMock {
final String apiAccessGroup = "00000000-0000-0000-0000-000000000000";
#Bean
#Primary
public UserDetailsService userDetailsService() {
User ericssonUser = new User("ericsson-worker", "secret", Arrays.asList());
User msApiUser = new User("msApiUser", "StrongPass", Arrays.asList(new SimpleGrantedAuthority(apiAccessGroup)));
return new InMemoryUserDetailsManager(Arrays.asList(
ericssonUser, msApiUser
));
}
}
and this my test Class any help please!!!!
#SpringBootTest(
classes = UserDetailsMock.class
)
#AutoConfigureMockMvc
public class MuninServiceAuthorizationTest {
#Autowired
MockMvc mockMvc;
List<MockHttpServletRequestBuilder> endpoints;
#BeforeEach
public void setUp() throws IOException {
MockitoAnnotations.openMocks(this);
endpoints = Arrays.asList(
MockMvcRequestBuilders.post("/migrate/foss").with(csrf()),
MockMvcRequestBuilders.get("/swagger/ui/**"));
}
#Test
#WithUserDetails("msApiUser")
void userWithGroupWhichIsAllowedToUseApiShouldGet200() throws Exception {
for (MockHttpServletRequestBuilder mockHttpServletRequestBuilder : endpoints) {
mockMvc.perform(mockHttpServletRequestBuilder)
.andExpect(status().isOk());
}
}
}
I'm trying to test my controller and I want to my custom DispatcherServlet include on that.
my dispatcher is something like this:
public class LoggableDispatcherServlet extends DispatcherServlet {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggableDispatcherServlet.class);
#Autowired
private LogsService logsService;
#Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws
Exception
{
.
.
.
mapper.readTree(requestWrapper.getContentAsByteArray());
int status = responseWrapper.getStatus();
JsonNode newNode = mapper.readTree(responseWrapper.getContentAsByteArray());
JsonNode responseJson= newNode;
logsService.addLogs(request,response ,...)
}
}
and my test Class is something like this:
#SpringBootTest
#RunWith(SpringRunner.class)
public class RestControllerTest {
private final Resource test1 = new ClassPathResource("test1.json");
private MockMvc mockMvc;
#Autowired
private RestTemplate restTemplate;
#Autowired
private WebApplicationContext wac;
#BeforeEach
public void before() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
this.mockRestServiceServer = MockRestServiceServer.bindTo(this.restTemplate)
.build()
}
#Test
public void getAvailableLoanTest() throws Exception{
String url1="http://localhost:80801/testService?param1=1¶m2=2";
this.mockRestServiceServer
.expect(ExpectedCount.manyTimes(), requestTo(url1))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(this.test1, MediaType.APPLICATION_JSON_UTF8));
this.mockMvc.perform(post("/api/myApi")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(new MyRequest(1, 2,))))
.andExpect(status().is2xxSuccessful())
.andExpect(content().contentType("application/json"))
//.andExpect(jsonPath("#.res1").value(1L))
.andReturn();
.
.
.
}
}
The problem is my request receive directly by rest controller and I can't test the DispatcherServlet.
I'm using spring boot 2.2.3 with jar packaging and I don't have web.xml or any servlet configration.
I have a spring boot REST API with a GET method that returns data available in a DB. I am attempting to write an integration test to test this API method. I have configured the test to use the H2 database. I am trying to add some mock data to the database before the test is executed and see if the API retrieves that data. Following is the code I have written so far.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#TestPropertySource(locations = "classpath:application-test.properties")
public class MetaControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private ProvinceDAO provinceDAO;
#Transactional
#Before
public void addData () {
Province southern = getProvinceEntity("Southern", "දකුණ", "தென்");
provinceDAO.createEntity(southern);
System.out.println(provinceDAO.findAll(Province.class).size());
}
#Test
public void testGetProvinces() throws Exception {
MvcResult result = mvc.perform(get("/meta/provinces"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andReturn();
System.out.println(result.getResponse().getContentAsString());
}
}
However, when I run this code, I am getting an error saying "org.springframework.dao.InvalidDataAccessApiUsageException: No transactional EntityManager available; nested exception is java.lang.IllegalStateException: No transactional EntityManager available"
I have also attempted using #MockBean instead of #Autowired to bind the provinceDAO. Even though this prevents the error, it does not persist the entity in the database.
How should I write my testcase to test my method here?
Update:
application-test.properties
spring.datasource.url = jdbc:h2:mem:test
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
Entity -> Province.java
#Entity
#Table(name = "w4a_province")
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "province_name")
private String name;
#Column(name = "province_name_si")
private String nameSi;
#Column(name = "province_name_ta")
private String nameTa;
.
.
}
GenericDAO.java
#Repository
public class GenericDAO<T> implements IGenericDAO<T> {
#PersistenceContext
private EntityManager em;
#Override
public Session getCurrentSession() {
return this.em.unwrap(Session.class);
}
#Override
public T findByPrimaryKey(Class<T> clazz, Object primaryKey) {
return getCurrentSession().find(clazz, primaryKey);
}
#Override
public List<T> findAll(Class<T> clazz) {
DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
return criteria.getExecutableCriteria(getCurrentSession()).list();
}
#Override
public T createEntity(T entity) {
getCurrentSession().save(entity);
return entity;
}
ProvinceDAOImpl.java
#Repository
public class ProvinceDAOImpl extends GenericDAO<Province> implements ProvinceDAO {
}
MetaController.java
#RestController
#PreAuthorize("permitAll()")
public class MetaController {
private final MetaService metaService;
#Autowired
public MetaController(MetaService metService) {
this.metaService = metService;
}
#GetMapping("/meta/provinces")
public ResponseEntity<List<ProvinceDTO>> getProvinces() {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving list of provinces.");
}
List<ProvinceDTO> provinces = metaService.getProvinces();
return ResponseEntity.ok(provinces);
}
}
MetaServiceImpl.java
#Service
#Transactional
public class MetaServiceImpl implements MetaService {
private final ProvinceDAO provinceDAO;
#Autowired
public MetaServiceImpl(ProvinceDAO provnceDAO) {
this.provinceDAO = provnceDAO;
}
public List<ProvinceDTO> getProvinces() {
if (logger.isDebugEnabled()) {
logger.debug("Obtaining a list of provinces from database.");
}
List<Province> entities = provinceDAO.findAll(Province.class);
if (logger.isDebugEnabled()) {
logger.debug("Converting province entities to dtos.");
}
List<ProvinceDTO> dtos = new ArrayList<>();
for (int i = 0; i < entities.size(); i++) {
Province entity = entities.get(i);
if (LocaleContextHolder.getLocale().getLanguage().equals(
GlobalConstants.LanguageIdentifiers.SINHALA_LANGUAGE_TAG)) {
dtos.add(new ProvinceDTO(entity.getId(), entity.getNameSi()));
} else if (LocaleContextHolder.getLocale().getLanguage().equals(
GlobalConstants.LanguageIdentifiers.TAMIL_LANGUAGE_TAG)) {
dtos.add(new ProvinceDTO(entity.getId(), entity.getNameTa()));
} else {
dtos.add(new ProvinceDTO(entity.getId(), entity.getName()));
}
}
return dtos;
}
}
I managed to feed the database with the required data by placing a SQL script data-h2.sql with insert queries at the test/resources folder. This prevented the requirement to use an EntityManager or a DAO.
Furthermore, I added the following property to the application-test.properties file.
spring.datasource.platform=h2
In Order to test Rest Api You can try functional test as well as integration test.
You can prepare your own response formate as required and check whether the same is returned or else you can also verify whether the data from db is fine or not.Plz check the below example
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = FactsMain.class)
#WebAppConfiguration
public abstract class BaseTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected String mapToJson(Object obj) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
}
In First test case i am forming the response format and trying to return the same and then validating the same.Here i don't need the db data so i have kept service as mock instead of auto wired.And used ObjectMapper for converting json to java and then java obj to json from base Test class.
public class PersonalDetailsControllerTest extends BaseTest {
#MockBean
private IPersonalService service;
private static final String URI = "/api/personalDetails";
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void testGet() throws Exception {
PersonalDetailsEntity entity = new PersonalDetailsEntity();
List<PersonalDetailsEntity> dataList = new ArrayList<PersonalDetailsEntity>();
FactsAdminResponse<PersonalDetailsEntity> dataResponse = new FactsAdminResponse<PersonalDetailsEntity>();
entity.setId(1);
entity.setName(“Anthony Holmes”);
entity.setAge(26);
entity.setCity(“Banglore”);
entity.setCountry(“India”);
dataList.add(entity);
dataResponse.setData(dataList);
Mockito.when(service.getBuildings()).thenReturn(dataList);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(URI)
.accept(MediaType.APPLICATION_JSON);
MvcResult mvcResult = mvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
String expectedJson = this.mapToJson(dataResponse);
String outputInJson = mvcResult.getResponse().getContentAsString();
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertEquals(expectedJson, outputInJson);
}
}
In below case we are getting the actual data in json format as we are doing rest api call and then just validating the status apart from status you can also cross check the data
public class PersonalDetailsControllerTest extends BaseTest {
private static final String URI = "/api/personalDetails";
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void getGet() throws Exception {
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(URL)
.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
//you got the content in string format now you can also validate the data
}
I am new to sprint-boot. I have a spring-boot application which is working fine in it's regular path. Now as I am trying to write unit/integration tests, I find that my beans are null.
I appreciate any help on understanding why are they null and how to fix it. It seems that it is not able to pick up properties from the yml at all.Please let me know if any more clarification is required.
To clarify the structure:
The main class:
#SpringBootApplication
#EnableConfigurationProperties(ApplicationConfiguration.class)
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
}
}
The properties file (src/main/java/resources/application.yml)
http:
url:
protocol: http
baseUrl: ${CONNECTOR_BASE_URL}
connectorListUrl : connectors
The configuration class that is using the above properties (ApplicationConfiguration.java) is :
#ConfigurationProperties(prefix = "http.url")
#Validated
#Data
public class ApplicationConfiguration {
private String protocol;
private String baseUrl;
private String connectorListUrl;
}
Now, the simplified version of the class(ContinuousMonitorServiceTask.java that I am trying to write my test on, looks like :
#Component
#Slf4j
public class ContinuousMonitorServiceTask extends TimerTask {
#Autowired MonitorHttpClient httpClient;
#Autowired ApplicationConfiguration config;
#PostConstruct
public void setUp() {
connectorListUrl =
config.getProtocol() + "://" + config.getBaseUrl() + "/" + config.getConnectorListUrl();
connectorListHeaderParams.clear();
connectorListHeaderParams.put("Accept", "application/json");
connectorListHeaderParams.put("Content-Type", "application/json");
connectorListGetRequest = new HttpGet(connectorListUrl);
httpClient.setHeader(connectorListGetRequest, connectorListHeaderParams);
}
public void fetchList() {
try {
response = httpClient.callApi("Get Connector List", connectorListGetRequest);
log.info(response.toString());
connectorListResponseHandler(response);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
The above code is working fine when I am executing.
Now when I am writing test, I need to mock api calls and hence, I have used MOCK-SERVER and my testSimple1 test has passed which is a simple test to see if the mock server can start and return expected response. However, while debugging simpleTest2, I am seeing
monitorTask is null
appConfig is null
monitorTask is null
Although, I have src/test/resources/application.yml as:
http:
url:
protocol: http
baseUrl: 127.0.0.1:8080
connectorListUrl : connectors
My guess is that appConfig is not able to pick up the properties from application.yml during test and hence everything is null.However, I am not 100% sure about what is happening in real time.
Here is how my test class looks like (Kind of dirty code, but I am putting it in it's current state to show what I have tried so far):
//#RunWith(MockitoJUnitRunner.class)
//#TestPropertySource(locations="classpath:application.yml")
//#RunWith(SpringJUnit4ClassRunner.class)
//#SpringApplicationConfiguration(ApplicationConfiguration.class)
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ApplicationConfiguration.class)
//#EnableConfigurationProperties(ApplicationConfiguration.class)
public class ContinousMonitorTest {
private MockMvc mockMvc;
#Mock private MonitorHttpClient httpClient;
#Mock private ApplicationConfiguration appConfig;
#InjectMocks
//#MockBean
//#Autowired
private ContinuousMonitorServiceTask monitorTask;
TestRestTemplate restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
private static ClientAndServer mockServer;
#BeforeClass
public static void startServer() {
mockServer = startClientAndServer(8080);
}
#AfterClass
public static void stopServer() {
mockServer.stop();
}
private void createExpectationForInvalidAuth() {
new MockServerClient("127.0.0.1", 8080)
.when(
request()
.withMethod("GET")
.withPath("/validate")
.withHeader("\"Content-type\", \"application/json\""),
//.withBody(exact("{username: 'foo', password: 'bar'}")),
exactly(1))
.respond(
response()
.withStatusCode(401)
.withHeaders(
new Header("Content-Type", "application/json; charset=utf-8"),
new Header("Cache-Control", "public, max-age=86400"))
.withBody("{ message: 'incorrect username and password combination' }")
.withDelay(TimeUnit.SECONDS,1)
);
}
private GenericResponse hitTheServerWithGETRequest() {
String url = "http://127.0.0.1:8080/validate";
HttpClient client = HttpClientBuilder.create().build();
HttpGet post = new HttpGet(url);
post.setHeader("Content-type", "application/json");
GenericResponse response=null;
try {
StringEntity stringEntity = new StringEntity("{username: 'foo', password: 'bar'}");
post.getRequestLine();
// post.setEntity(stringEntity);
response=client.execute(post, new GenericResponseHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
return response;
}
#Test
public void testSimple1() throws Exception{
createExpectationForInvalidAuth();
GenericResponse response = hitTheServerWithGETRequest();
System.out.println("response customed : " + response.getResponse());
assertEquals(401, response.getStatusCd());
monitorTask.fetchConnectorList();
}
#Test
public void testSimple2() throws Exception{
monitorTask.fetchConnectorList();
}
as #second suggested above, I made a change in the testSimple2 test to look like and that resolved the above mentioned problem.
#Test
public void testSimple2() throws Exception{
mockMvc = MockMvcBuilders.standaloneSetup(monitorTask).build();
Mockito.when(appConfig.getProtocol()).thenReturn("http");
Mockito.when(appConfig.getBaseUrl()).thenReturn("127.0.0.1:8080");
Mockito.when(appConfig.getConnectorListUrl()).thenReturn("validate");
Mockito.when(httpClient.callApi(Mockito.any(), Mockito.any())).thenCallRealMethod();
monitorTask.setUp();
monitorTask.fetchConnectorList();
}
Alternatively, could have done:
#Before
public void init()
{
MockitoAnnotations.initMocks(this);
}
I'm having issue unit testing a camel route which uses rabbitmq for the broker.
I've been researching for weeks but haven't found an effective way to do this.
Firstly, I was having an issue with NOT calling rabbitmq in my test, and to keep this a unit test and not an integration test. This was achieved by using advicewith and switch out the queue for mock queues.
However, with the following code the messages are not reaching the result or end queue (MOBILE_QUEUE).
java.lang.AssertionError: mock://result Received message count. Expected: <1> but was: <0>
Expected :<1>
Actual :<0>
Here is my route, which imports rabbitmq.class
from(TEST_QUEUE).to(MOBILE_QUEUE).routeId("test2phone");
My config rabbitmq.class
#Component
public class RabbitMQ extends Properties {
public final String TEST_QUEUE = CreateRabbitMQQueue("TestQueue", "camel");
public final String MOBILE_QUEUE = CreateRabbitMQQueue("MobileQueue", "camel");
public static String CreateRabbitMQQueue(String QueueName, String RoutingKey)
{
String hostv;
String portv;
String username;
String password;
hostv = "mq-staging";
portv = System.getenv("SERVICE_PORT_AMQP");
username = System.getenv("V_RABBIT_USERNAME");
password = System.getenv("V_RABBIT_PASSWORD");
UriComponentsBuilder uriBuilder = UriComponentsBuilder
.fromPath("/" )
.scheme("rabbitmq")
.host(hostv)
.port(portv)
.path("/" + QueueName)
.queryParam("username",username)
.queryParam("password", password)
.queryParam("routingKey",RoutingKey)
.queryParam("queue","Q" + QueueName);
return uriBuilder.toUriString();
}
}
And my unit test
#RunWith(CamelSpringRunner.class)
#MockEndpoints
#UseAdviceWith
#SpringBootTest
public class RouteTester extends CamelTestSupport {
String TEST_QUEUE;
String MOBILE_QUEUE;
#Autowired
Routes routes;
#Autowired
CamelContext context;
#Autowired
ProducerTemplate template;
#Before
public void setUp() throws Exception {
TEST_QUEUE = routes.getTEST_QUEUE();
MOBILE_QUEUE = routes.getMOBILE_QUEUE();
context.getRouteDefinition("test2phone").adviceWith(context, new Routes() {
#Override
public void configure() throws Exception {
interceptSendToEndpoint(TEST_QUEUE)
.skipSendToOriginalEndpoint()
.to("mock:testQ");
interceptSendToEndpoint(MOBILE_QUEUE)
.skipSendToOriginalEndpoint()
.to("mock:result");
}
});
context.start();
}
#Test
public void testTest() throws Exception {
String body = "hello123";
MockEndpoint resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
resultEndpoint.expectedMessageCount(1);
resultEndpoint.expectedBodiesReceived(body);
template.sendBody(TEST_QUEUE, body);
resultEndpoint.assertIsSatisfied();
}
#After
public void TearDown() throws Exception {
context.stop();
}
}
interceptSendToEndpoint is useful to intercepting output endpoint. You probably want replace input endpoint and intercept output endpoint. See AdviceWith.
This should work:
context.getRouteDefinition("test2phone").adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith("direct:test");
interceptSendToEndpoint(MOBILE_QUEUE)
.skipSendToOriginalEndpoint()
.to("mock:result");
}
});
And test your route with:
template.sendBody("direct:test", body);