Currently I'm trying to work with Mockito combined with rest. I'm not sure how to test my edit method in rest with Mockito and rest. The last block of code contains the part I can't figure out atm. I haven't worked with Mockito before so all tips are welcome.
This is the functionality i want to test:
#POST
#Path("edit/{id}")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public Profile editProfile(Profile profile, #PathParam("id") Long id){
Profile updatedProfile = profileService.getProfile(id);
updatedProfile.setBiography(profile.getBiography());
updatedProfile.setLocation(profile.getLocation());
updatedProfile.setWebsite(profile.getWebsite());
updatedProfile.setAvatar(profile.getAvatar());
updatedProfile.setImage(profile.getImage());
updatedProfile.setUpdated_at(new Date());
return updatedProfile;
}
Setting up my TestClass here
Client client;
WebTarget root;
static final String PATH = "/MyApp/api/profile/";
static final String BASEURL = "http://localhost:8080" + PATH;
List<Profile> profileList = new ArrayList<Profile>();
Profile profile;
#Mock
ProfileDao profileDao;
#InjectMocks
private ProfileService profileService;
#Before
public void setUp() {
this.client = ClientBuilder.newClient();
this.root = this.client.target(BASEURL);
profile = new Profile(1L,"biography", "location" ,"website","../avatar.jpg","../image.jpg" );
for(int i = 0; i < 10; i++){
profileList.add(profile);
}
}
The Test function to edit an test: /profile/edit/1 - /profile/edit/{id}
// This part doesn't work. I'm not sure how to handle this part with mockito and rest
#Test
public void editProfileTest() {
String mediaType = MediaType.APPLICATION_JSON;
when(profileDao.find(1L)).thenReturn(new Profile(1L,"biography", "location" ,"website", "../avatar.jpg","../image.jpg"));
final Entity<Profile> entity = Entity.entity(profileService.getProfile(1L), mediaType);
Profile profileResult = this.root.path("edit/1").request().post(entity, Profile.class);
assertThat(profileResult, is(profile)); // this doesn't match
}
At first I wasn't really sure how to make the test valid but with the following piece of code I solved my problem.
Adjusted my Rest / Mockito test a little bit:
#Test
public void editProfileTest() {
String mediaType = MediaType.APPLICATION_JSON;
when(profileDao.find(2L)).thenReturn(profileList.get(0));
final Entity<Profile> entity = Entity.entity(profileService.getProfile(2L), mediaType);
Profile profileResult = this.root.path("edit/2").request().post(entity, Profile.class);
assertThat(profileResult.getId(), is(profileService.getProfile(2L).getId()));
assertThat(profileResult.getUser_id(), is(profileService.getProfile(2L).getUser_id()));
assertThat(profileResult.getAvatar(), is(profileService.getProfile(2L).getAvatar()));
assertThat(profileResult.getBiography(), is(profileService.getProfile(2L).getBiography()));
assertThat(profileResult.getLocation(), is(profileService.getProfile(2L).getLocation()));
assertThat(profileResult.getWebsite(), is(profileService.getProfile(2L).getWebsite()));
assertThat(profileResult.getImage(), is(profileService.getProfile(2L).getImage()));
}
This is testing the method on /MyApp/profile/edit/{id} only. If you have examples for an integration test or references feel free to post about it. As I'm trying to learn some more about testing in general.
Related
I wanted to make an connection between frontend and backend so I used #CrossOrigin annotation Like below.
#CrossOrigin(origins = "http://localhost:3000, http://server ip:3000, http://backend.com:3000")
#RestController
#RequestMapping("/member")
public class MemberController {
Logger logger = LoggerFactory.getLogger(MemberController.class);
private MemberService ms;
private Encryption encrypt;
private S3FileUploadService sfu;
#Autowired
public MemberController(MemberService ms, Encryption encrypt,S3FileUploadService sfu) {
this.ms = ms;
this.encrypt = encrypt;
this.sfu = sfu;
}
#GetMapping("/login")
public FrontMember login(#RequestHeader("Authorization") String autho) {
logger.info("Authorization : " + autho);
String memberInform = encrypt.aesDecrypt(autho);
String[] idPwd = memberInform.split("/");
Member loginTry = new Member();
loginTry.setEmail(idPwd[0]);
loginTry.setPwd(encrypt.shaEncryption(idPwd[1]));
Member authorizedUser = ms.login(loginTry);
if(authorizedUser == null){
logger.warn("No member info");
return null;
}else{
logger.info("Member Get : "+authorizedUser.toString());
String hashMemberNum = encrypt.aesEncrypt(Integer.toString(authorizedUser.getMemberNum()));
String mgHash = encrypt.aesEncrypt(Integer.toString(authorizedUser.getMg()));
FrontMember fm = new FrontMember(hashMemberNum, authorizedUser.getNickName(), authorizedUser.getPfUrl(),mgHash);
logger.info("Login User : "+fm.toString());
return fm;
}
}
}
But it doesn't work unless I only put one domain on origin like below.
#CrossOrigin(origins = "http://localhost:3000")
I want to put several domain at crossorigin.
How can I solve this problem?
Check the Official document of CrossOrign,we can found below description:
So the reason is that you have made a wrong invocation,if you need to allow multiple origins,you need to use an array contains of string instead of single string
In order to make your code work,you can try with below:
#CrossOrigin(origins = {"http://localhost:3000", "http://server ip:3000", "http://backend.com:3000"})
#RestController
#RequestMapping("/member")
public class MemberController {
}
I have a Java Springboot web API project that uses Azure table storage as the data store. I'd like to create a unit test to make sure that the repository is properly converting an Azure TableEntity into a custom Tag object in the repository. However, I am not able to figure-out a way to mock the Azure PagedIterable<TableEntity> that is returned by the Azure TableClient.listEntities() function.
At the core of my repository class is the following function that returns a filtered list of table entities:
private PagedIterable<TableEntity> getFilteredTableRows(String filter, String tableName) {
ListEntitiesOptions options = new ListEntitiesOptions().setFilter(filter);
TableClient tableClient = tableServiceClient.getTableClient(tableName);
PagedIterable<TableEntity> pagedIterable = tableClient.listEntities(options, null, null);
return pagedIterable;
}
How do I ensure the TableClient is mocked and returns a valid PagedIterable<TableEntity>?
Below is sample JUnit test class that uses Mockito to mock the Azure PagedIterable<T> object and return a single TableEntity that is mapped to a custom Tag model in the repository code.
The test setup requires four mocks:
A mock Iterator
A mock PagedIterable
A mock TableServiceClient
A mock TableClient
If there is an easier way to accomplish the same thing, I'm open to suggestions.
#ExtendWith(MockitoExtension.class)
#MockitoSettings(strictness = Strictness.LENIENT)
public class DocTagRepositoryTest {
#InjectMocks
#Spy
DocTagRepository docTagRepository;
#Mock
TableServiceClient tableServiceClient;
#Mock
TableClient tableClient;
private static TableEntity testTableEntity;
private static Tag testTagObject;
#SneakyThrows
#BeforeAll
public static void setup() {
loadTableObjects();
}
#Test
public void testGetTagList() {
// Given: A request to get tags from Azure table storage...
Iterator mockIterator = mock(Iterator.class);
when(mockIterator.hasNext()).thenReturn(true, false);
when(mockIterator.next()).thenReturn(testTableEntity);
PagedIterable mockPagedTableEntities = mock(PagedIterable.class);
when(mockPagedTableEntities.iterator()).thenReturn(mockIterator);
when(tableServiceClient.getTableClient(Mockito.anyString())).thenReturn(tableClient);
when(tableClient.listEntities(any(), any(), any())).thenReturn(mockPagedTableEntities);
List<Tag> expected = new ArrayList<>();
expected.add(testTagObject);
// When: A call is made to the repository's getActiveTags() function...
List<Tag> actual = docTagRepository.getActiveTags();
// Then: Return an array of tag objects.
assertArrayEquals(expected.toArray(), actual.toArray());
}
private static void loadTableObjects() {
OffsetDateTime now = OffsetDateTime.now();
String testUser = "buh0000";
String rowKey = "test";
String partitionKey = "v1";
String activeStatus = "A";
Map<String, Object> properties = new HashMap<>();
properties.put("createdDate", now);
properties.put("createdBy", testUser);
properties.put("modifiedDate", now);
properties.put("lastModifiedBy", testUser);
properties.put("status", activeStatus);
testTableEntity = new TableEntity(partitionKey, rowKey);
testTableEntity.setProperties(properties);
testTagObject = new Tag(partitionKey, rowKey, now, testUser, now, testUser, activeStatus);
}
}
I'm trying to write unit test case for HttpHandler class which has rest template call for delete. I've crated a usercontroller class to make resttemplate call in order to test the functionality of sendDelete in HttpHandler class. Can someone help me too understand what is the correct way to write unit test case for sendDelete method in HtttpHandler class?
I have a class HttpHandler. It has a function sendDelete where it calls resttemplate.exchange method
#Service
public class HttpHandler {
public <T,R> ResponseEntity<Void> sendDelete(String url, HttpHeaders httpHeaders, R requestBody, Class<T> responseClass) {
//create an instance of rest template
RestTemplate restTemplate = new RestTemplate();
HttpEntity<R> entity = new HttpEntity<R>(requestBody, httpHeaders);
logger.info("DELETE request to " + url + " with body: " + JsonUtil.jsonizeExcludeNulls(requestBody));
//make an HTTP DELETE request with headers
ResponseEntity<Void> response = restTemplate.exchange(url, HttpMethod.DELETE, entity, Void.class);
logger.info("DELETE" + url + ": " + JsonUtil.jsonize(response));
return response;
}
}
I'm using junit5. Below is the unit test case for sendDelete method in above class:
#LocalServerPort
private int port;
private String baseUrl;
#Autowired
private HttpHandler httpHandler;
#BeforeEach
public void setBaseUrl(){
this.baseUrl = "http://localhost:"+ port + "/users";
}
#Test
public void testSuccessDeleteUserById() throws Exception{
this.baseUrl = baseUrl + "/1";
//create headers
HttpHeaders httpHeaders = new HttpHeaders();
//set content type
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
//make an HTTP DELETE request with headers
ResponseEntity<Void> actual = httpHandler.sendDelete(baseUrl, httpHeaders, null, Void.class);
assertEquals(404, actual.getStatusCodeValue());
}
Below is the user controller class
#RestController
public class UserController {
#DeleteMapping("/users/{userId}")
public ResponseEntity<Void> deleteUser(#PathVariable("userId") int userId){
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
}
}
Thank you for your time!
There are two ways to do it.
Mocking RestTemplate. To do it, first, you have to make the RestTemplate a field, and inject it through the constructor (or any other way). This allows you to inject a mock object. Then, the rest is plain and simple mocking.
You can use MockWebServer. This way you do not need to change anything. It is just a web server that your method will send the request to. After the method call finishes, you can access the recorded request and make some validations.
Here's a crude example. If you will have a lot of those tests, then you can move the web server initialization to a #BeforeEach method and the destroying to #AfterEach method.
public class HttpHandlerTest {
private final HttpHandler handler = new HttpHandler();
#Test
#SneakyThrows
public void testDelete() {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.start(9889);
mockWebServer.enqueue(
new MockResponse().setResponseCode(200)
);
String url = "http://localhost:9889";
Hello hello = new Hello("hello world");
final ResponseEntity<Void> entity = handler.sendDelete(url, null, hello, Hello.class);
assertNotNull(entity);
assertEquals(200, entity.getStatusCode().value());
final RecordedRequest recordedRequest = mockWebServer.takeRequest();
assertEquals("DELETE", recordedRequest.getMethod());
mockWebServer.close();
}
}
// just an example class to use as a payload
class Hello {
String text;
public Hello() {
}
public Hello(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Note. Even though you will not opt for the first solution, I recommend you do abandon initializing RestTemplate for each request. You better use WebClient instead. If you do so, the first solution will not work anymore, while the second will remain intact.
I am trying to mock a function call to an external api that lives in an if statement. I am not able to return the value I have in .thenReturn, and I am not sure why. I have looked for answers to this on SO, but I can't seem to find anything that answers my question. Thanks a bunch for your time!
Here is my class I am testing:
#Service
public class TwilioVerifyService {
public String requestCode(String phoneNumber, String countryCode, String via) throws AuthyException
{
AuthyApiClient authyApiClient = new AuthyApiClient("<apiClient>");
Params params = new Params();
params.setAttribute("code_length", "6");
Verification verification = authyApiClient
.getPhoneVerification()
.start(phoneNumber, countryCode, via, params);
if (verification.isOk())
{
return "{ \"success\": \"Successfully sent verification code.\" }";
}
return "{ \"error\": \"Error sending code.\" }";
}
}
And here is my test:
#RunWith(MockitoJUnitRunner.class)
public class TwilioVerifyServiceTests {
#InjectMocks
TwilioVerifyService twilioVerifyService;
#Mock
Verification verification;
#Test
public void requestCodeTest_success() throws AuthyException
{
String phoneNumber = "1111111111";
String countryCode = "1";
String via = "1";
when(verification.isOk()).thenReturn(true);
String result = twilioVerifyService.requestCode(phoneNumber, countryCode, via);
System.out.println(result);
}
}
I believe I'm (or want to be) mocking out verification.isOk() to return true regardless of the inputs, but it seems to return false providing "{ "error": "Error sending code." }" instead of "{ \"success\": \"Successfully sent verification code.\" }".
Thanks again for your time!
Verification is generated from a call to methods in AuthyApiClient.
Ideally AuthyApiClient should not be instantiated in your service, but rather injected into it by the caller.
private AuthyApiClient authyApiClient;
#Autowired
public TwilioVerifyService(AuthyApiClient authyApiClient) {
this.authyApiClient = authyApiClient;
}
Then you can mock authyApiClient and pass it in to the class being tested:
TwilioVerifyService twilioVerifyService = new TwilioVerifyService(mockAuthyApiClient);
That gives you more control over the class being tested and removes the dependency it currently has on the AuthyApiClient constructor.
I'm trying to test a method intialize transaction where the method creates a unique transaction Id. This method uses reference of other class to retrieve the properties.
After mocking the reference classes am still getting null pointer exception. when i try to test. Below is my code.
Note: JMockito
Any help appreciated
public ResponseDto initializeTransaction(RequestDTO request){
try {
String transactionId =getTransactionId(request);
ResponseDTO result = new ResponseDTO();
result.setTransactionId(transactionId);
return result;
}
}
public String getTransactionId(CreditCardGwtInitializeRequestDTO request){
StringBuffer transactionId = new StringBuffer();
String customerId = customerIdentifier.getCustomer();
UserDto userDto = user.getUserDetails(request.getKey());
String userWorkStationId =userDto.getWorkStationId();
transactionId.append(String.valueOf(System.currentTimeMillis()) + "-");
transactionId.append(userDto.getObjId()+ "-");
transactionId.append(transactionIdEncode.encode(customerId));
transactionId.append("-");
transactionId.append(transactionIdEncode.encode(userWorkStationId));
return transactionId.toString();
}
Test class
public class CreditCardGwtInitializeServiceImplTest {
private CreditCardGwtInitializeServiceImpl test;
#Mock
private CustomerIdentifier customerIdentifier;
#Mock
private UserDto userDto;
#Mock
private UserDetails user;
private CreditCardGwtInitializeRequestDTO request;
#Mock
TransactionIdCharacterEncoding transactionId;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void when_profilename_notNull_retrieveByName() throws Exception {
//test.setUser(user);
CreditCardGwtInitializeResponseDTO expected = new CreditCardGwtInitializeResponseDTO();
expected.setGatewayPassKey("");
String profileName="theName";
String connectionKey ="123456";
String custId ="custId";
request.setGatewayProfile(profileName);
request.setConnectionKey(connectionKey);
//userDto.setWorkStationId("12345");
//userDto.setObjId(12345L);
when(customerIdentifier.getCustomer()).thenReturn(custId);
when(user.getUserDetails(anyString())).thenReturn(userDto);
when(userDto.getWorkStationId()).thenReturn("RTYTYU");
when(userDto.getObjId()).thenReturn(1232324L);
when(transactionId.encode(anyString())).thenReturn("01010101");
CreditCardGwtInitializeResponseDTO response = test.initializeTransaction(request);
assertEquals(expected,response );
verifyZeroInteractions(gatewayProfileRetrievalService);
}
By adding thes lines solved my problem
MockitoAnnotations.initMocks(this);
test = new CreditCardGwtInitializeServiceImpl();
test.setUser(user);
test.setCustomerIdentifier(customerIdentifier);
test.setTransactionIdEncode(transactionId);
Here is an alternative solution that uses Mockito magic instead of manual initialization (replaces the setup method).
First override the default JUnit Runner class by the one provided by mockito (this has the same effect as MockitoAnnotations.initMocks(this)):
#RunWith(MockitoJUnitRunner.class)
public class CreditCardGwtInitializeServiceImplTest {
...
then instantiate your object right after your declare it and let mockito take care of the injection (this has the same effect as the 5 lines of your solution) :
#InjectMocks
private CreditCardGwtInitializeServiceImpl test = new CreditCardGwtInitializeServiceImpl();
...