Spring Boot 2 MockMVC unit testing with RequestPart and MultipartFile - unit-testing

I have the below email controller for sending email with RequestPart DTO object (userDTO) and Multipart file (3 files upload max). where userDTO is a JSON object
I tried using postman and it works perfectly for sending email with attachments, however i need to develop unit testing using MockMVC and I am not able to find any suitable examples on these combinations of Multipart and Request Part. When i tried using the below test class, i'm not able to hit my controller which will trigger email.
My Controller
#PostMapping(path = "/api/email/sendEmail)
public ResponseEntity<UserDto> sendEmail(#RequestPart(value = "file", required = false) MultipartFile[] uploadfile,
#RequestPart UserDto userDTO, WebRequest webRequest) {
webRequest.setAttribute("userDTO", userDTO, RequestAttributes.SCOPE_REQUEST);
UserDto obj = emailService.sendEmail(userDTO, uploadfile);
return new ResponseEntity<>(obj, HttpStatus.OK);
}
My JSON (userDTO) which comes in request part
{
"sender":"sender#gmail.com",
"recipients":"receiver#gmail.com",
"subject":"Hi Testing Mail API",
"content":"This is my email"
}
My Test Class
#ContextConfiguration
#WebAppConfiguration
public class ServicesApplicationTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#Test
public void testEmail() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
mockMvc.perform(post("/api/email/sendEmail")
.contentType(MediaType.APPLICATION_JSON)
.content("{ \"sender\":\"sender#gmail.com\",\"recipients\":\"receiver#gmail.com\",\"subject\":\"Hi Testing Mail API\",\"content\":\"This is my email\"}")
.accept(MediaType.APPLICATION_JSON));
}
Any leads would be much appreciated. Thanks

Related

How to write a Unitest case for the apache camel routing in the springboot application

I have been assigned to write unit tests for the Springboot application uses Apache Camel for routing.
Below is a simple routing class.
#Component
public class MyRouteBuilder extends RouteBuilder
{
#Override
public void configure() throws Exception {
super.configure();
from("direct:encrypt").bean(ProcessData.class, "process(${exchange})").end();
}
}
How to write a Unit test for this. The application uses Mockito for writing the testcases for other part of the application.
Please help. Thanks.
Have a look at the documentation about Camel and SpringBoot. There is a section about Testing with JUnit 4 and 5.
Here is an example for Camel 3, SpringBoot 2 and JUnit 5
#CamelSpringBootTest
#SpringBootTest
class MyRouteTest {
#Autowired
private CamelContext camelContext;
#Autowired
private ProducerTemplate producer;
private MockEndpoint mockEndpoint;
#BeforeEach
public void doBeforeEveryTest() {
MockEndpoint.resetMocks(camelContext);
}
#Test
void testWhateverRouteDetail() throws Exception {
mockEndpoint = camelContext.getEndpoint("mock:output", MockEndpoint.class);
mockEndpoint.expectedBodiesReceivedInAnyOrder(yourExpectedBody);
producer.sendBodyAndHeader("direct:encrypt", myBodyContent, headerName, headerValue);
mockEndpoint.assertIsSatisfied();
}
}

PowerMock mock injected Authentication

i am using PowerMockRunner in a spring-boot application for testing. Everything is working but when my controllers actions definition contain someControllerMethod(..., Authentication auth, ...). Then auth is null and therefore some code is not working.
What i tried is to mock Authentication and SecurityContext. Came up with something like this
private void mockSecurity() {
Authentication authentication = mock(Authentication.class);
SecurityContext securityContext = mock(SecurityContext.class);
List<SimpleGrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("USER"));
User mockedUser = new User("testuser", "passwordtest", authorities);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
when(SecurityContextHolder.getContext().getAuthentication().getDetails()).thenReturn(mockedUser);
when(SecurityContextHolder.getContext().getAuthentication().getName()).thenReturn(mockedUser.getUsername());
}
Now those mocks work, if my code uses SecurityContextHolder.getContext().getAuthentication() method of accessing the authentication, but not for the one automatically injected (probably because it is not yet mocked when the controller mock is created).
Any ideas how to mock the injected Authentication so the code does not need to be changed? spring-security-testand #MockWithUser have the same result.
Relevant parts of the test look like this,
#RunWith(PowerMockRunner.class)
public class UserControllerTest {
#InjectMocks
UserController userController;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = standaloneSetup(userController).build();
}
#Test
public void getUserDetails() {
mockSecurity();
mockMvc.perform(...).andExpect(...);
}
}
Edit as requested by pvpkiran the controller code
#RequestMapping(...)
public void getDetails(#PathVariable String id, Authentication auth) {
UserDetails loadedDetails = userService.getUserDetails(id);
if (!loadedDetails.getUserId().equals(auth.getName())) {
throw new Exception(...);
}
...
}

SpringBootTest - Test exception when request is invalid

I developed an API using web-flux which is working fine when I make request using POSTMAN. My code is:
Controller:
#PostMapping("/post", produces = ["application/xml"])
fun post(#Valid request: RequestData): Mono<Response> {
return Mono.just(request)
...
...
...
}
dto:
data class RequestData(
#get:NotBlank
#get:Email
val email: String = "",
)
So whenever I pass invalid email via POSTMAN, I'm catching the exception like below and its working:
#ExceptionHandler
fun bindingExceptionHandler(e: WebExchangeBindException) = "Custom Error Message"
But now when I write UT(#WebFluxTest) for this case (Invalid emaid), It failed.
#Test
fun testWhenInvalidEmail() {
// Request body
val email = "invalidemail"
val request = LinkedMultiValueMap<String, String>()
request.add("email", email)
webTestClient.post().uri("/post")
.body(BodyInserters.fromFormData(request))
.exchange()
.expectStatus().isOk
}
When I debug this, I found that my exceptionHandler not coming into picture when request coming through unit test. I'm using application/x-www-form-urlencoded content type in POST request.
Please let me know where I'm doing wrong.
I followed this question as well but didn't work.
As mentioned on another related question, this has been fixed in Spring Boot 2.1.0.
Also, you shouldn't have to build WebTestClient yourself but instead inject it in your test class (see reference documentation about that):
#RunWith(SpringRunner.class)
#WebFluxTest(MyValidationController.class)
public class MyValidationControllerTests {
#Autowired
private WebTestClient webClient;
#Test
public void testWhenInvalidEmail() {
//...
}
}

How do I unit test streaming download using jersey / dropwizard?

I have a resource method which produces a streaming download:
#GET
#Path("/{assetId}")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response download(#PathParam("assetId") String assetId) {
StreamingOutput stream = os -> service.download(assetId, os);
return Response.ok(stream).build();
}
I want to unit test this with a mock service object. I already have:
private static AssetsService service = Mockito.mock(AssetsService.class);
#ClassRule
public final static ResourceTestRule resource = ResourceTestRule.builder()
.addResource(new AssetsResource(service))
.addProvider(MultiPartFeature.class)
.build();
#Test
public void testDownload() {
reset(service);
// how to get an output stream from this?
resource.client().target("/assets/123").request().get();
}
Per my comment in the test, what do I need to do in order to get an outputstream from the response? I find the jersey client API pretty confusing.
Once I have this, I'll stub the service call so that it writes a known file, and test that it's received correctly.
Try this:
Response response = resource.client().target("/assets/123").request().get();
InputStream is = response.readEntity(InputStream.class);

share with facebook using Spring-Social and Spring Security

I have integrated social sign-in button [Facebook] with my web application. Its working fine using spring-social and spring security.
In my login.jsp I have:
<!-- Add Facebook sign in button -->
<button class="btn btn-facebook"><i class="icon-facebook"></i>facebook</button>
Now my registrion controller is: This is the place where I am getting a callback from facebook when the user tries to login for the first time from facebook and register the user in my Database.
#RequestMapping(value = "/user/register", method = RequestMethod.GET)
public String showRegistrationForm(WebRequest request, Model model)
{
LOGGER.debug("Rendering registration page.");
#SuppressWarnings("deprecation")
Connection<?> connection = ProviderSignInUtils.getConnection(request);
RegistrationForm registration = createRegistrationDTO(connection);
LOGGER.debug("Rendering registration form with information: {}", registration);
model.addAttribute(MODEL_NAME_REGISTRATION_DTO, registration);
return VIEW_NAME_REGISTRATION_PAGE;
}
And also the user is getting saved in UserConnection table.
For subsequent login also I am getting the updated connection in my WebRequest
Now I want to create a shareWithFacebook operation for a user who logged in in my application using signwithfacebook button.
For this my controller is:
#RequestMapping(method = RequestMethod.GET)
public String shareWithFacebook(WebRequest request){
Map<String, String[]> params = request.getParameterMap();
String[] head = request.getAttributeNames(WebRequest.SCOPE_REQUEST);
String[] head1 = request.getAttributeNames(WebRequest.SCOPE_SESSION);
return null;
}
Now when I am running this controller in debug mode , then I can see the Connection object is present in my WebRequest object in this controller,
How I can use this connection Object to make any operation, please help
no help from stackoverflow: but actually I got the solution , may it help someone else, thus posting the same:
add this in your social-xml config to initialize FacebookApiHelper
<bean id="facebookApiHelper" class="org.springframework.social.facebook.config.support.FacebookApiHelper">
<constructor-arg index="0" ref="usersConnectionRepository"/>
<constructor-arg index="1" ref="userIdSource"/>
</bean>
Then use the same in ur contoller to work with existing connection object with facebook.
#Controller
#RequestMapping("/facebook")
public class FacebookOperationController {
private static final Logger logger = LoggerFactory.getLogger(FacebookOperationController.class);
#Autowired
protected FacebookApiHelper facebookApiHelper;
#Autowired
UserIdSource userIdSource;
private UsersConnectionRepository usersConnectionRepository;
#Autowired
public FacebookOperationController(UsersConnectionRepository usersConnectionRepository)
{
this.usersConnectionRepository = usersConnectionRepository;
}
#RequestMapping(method = RequestMethod.GET)
public String shareWithFacebook(WebRequest request,Model model){
Facebook facebook = facebookApiHelper.getApi();
Connection<Facebook> connection = usersConnectionRepository.createConnectionRepository(userIdSource.getUserId()).findPrimaryConnection(Facebook.class);
return "tilesname";
}
}
Now we have connection and facebook , enjoy will all api..