0

I had created a JWTCreateImpl class given below to generate a jwt token using generatToken() method and respond a jwt string using loginUser() method. loginUser() method takes email and password as a parameter coming from frontend. This email is compare with email exist in database and if email is not present the errorResponse will become "email not exist" similarly do for password doesn't match. And lastly if email and password exist for a particular id then extracting the result from database and pass only uuid of user to generate a token and response will be jwt string. I want to perform unit testing for this class using Junit4, how can I write the test case using Junit4 for this?

JWTCreateImpl class Implements JWTCreate Interface which Contains abstract Methods loginUser(UserInfoJWT userInfoJWT) and generateToken(UUID uuid) and one String JWT_TOKEN_KEY which is used in generateToken() method mainly use with HMAC256 Algorithm. UserInfoJWT is a POJO class Which contains email and password of user.

ResponseJWT is a POJO class which contains UserToken and errorResponse.

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.knoldus.magad.jwt.api.JWTCreate;
import com.knoldus.magad.jwt.model.ResponseJWT;
import com.knoldus.magad.jwt.model.UserInfoJWT;
import com.knoldus.magad.dao.model.UserInfo;
import com.knoldus.magad.user.api.UserInfoProcessingAPI;

import org.apache.log4j.Logger;


import java.io.UnsupportedEncodingException;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class JWTCreateImpl implements JWTCreate {
private static final Logger LOGGER = Logger.getLogger(JWTCreateImpl.class);
private UserInfo existingUser;
private ResponseJWT response;
private  UserInfoProcessingAPI userInfoProcessingAPI;
private static final String NO_USER_EMAIL = "Email doesn't exists..";
private static  final String LOGIN_UNSUCCESSFUL = "Wrong Password";


@Override
public CompletableFuture<String>loginUser(final UserInfoJWT userInfoJWT) {
    return userInfoProcessingAPI.getUserInfo(userInfoJWT.getUserEmail()).thenApply(result -> {
        existingUser = result.orElse(null);
        if (existingUser == null) {
            response = ResponseJWT.builder().errorResponse(NO_USER_EMAIL).build();
        } else {
            final String dataBasePassword = existingUser.getUserPassword();
            if (userInfoJWT.getUserPassword().equals(dataBasePassword)) {
                response = ResponseJWT.builder().userToken(generateToken(existingUser.getUuid())).build();
            } else {
                response = ResponseJWT.builder().errorResponse(LOGIN_UNSUCCESSFUL).build();
            }
        }
        return response.toString();
    });
}
@Override
public String generateToken(final UUID uuid) {
    try {
        final Algorithm algorithm = Algorithm.HMAC256(JWT_TOKEN_KEY);
        final Date expirationDate = Date.from(ZonedDateTime.now().plusHours(24).toInstant());
        final Date issuedAt = Date.from(ZonedDateTime.now().toInstant());
        final String id = String.valueOf(uuid);
        final String issuer = "MagADAuth";
        return JWT.create()
                .withIssuedAt(issuedAt) // Issue date.
                .withExpiresAt(expirationDate) // Expiration date.
                .withClaim("userId", id)
                .withIssuer(issuer) // Issuer of the token.
                .sign(algorithm); // And the signing algorithm.
    } catch (UnsupportedEncodingException | JWTCreationException e) {
        LOGGER.error(e.getMessage(), e);
    }
    return null;
}

1 Answers1

1

As We all know Unit testing is testing small part of the application independently that means in our case method should be tested independently

In your case loginUser method of JWTCreateImpl Class is actually dependent on object UserInfoJWT,UserInfoProcessingAPI so in order to unit test loginUser method

  • we need to mock UserInfoJWT class so that it will return us email which is actually required input to the method
  • we also need to mock UserInfoProcessingAPI so that it will return User
  • finally we also need to call real method loginUser method in our unit test case(Also we need to test loginUser method for every possible condition with individual of unit tests)
  • In case of generateToken method we also need to provide UUID mock to unit test.

I would prefer Mockito with Junit for above case Refer links

What is Mocking? Why to use Mockito?

EDIT AS PER COMMENT

@RunWith(MockitoJUnitRunner.class)
public class JWTCreateImplTest {

    /* class under test should not be mocked */
    private JWTCreateImpl jwtCreateImpl;

    /* Mocking UserInfoProcessingAPI as it is dependency of JWTCreateImpl */
    @Mock
    private UserInfoProcessingAPI infoProcessingAPI;

    /*Mockito method which setup everything before test actually start (All Object Initialization can be done here */
    @Before
    public void setup() {
        jwtCreateImpl = new JWTCreateImpl();
    }

    /* Testing Happy flow */
    @Test
    public void testNotNullJwtToken() {
        Mockito.when(infoProcessingAPI.getUserInfo(getUser().getUserEmail())).thenReturn(getAppUser());
        CompletableFuture<String> jwtToken = jwtCreateImpl.loginUser(getUser());
        Assert.assertNotNull(jwtToken);
    }

    /* Testing when null email is passed */
    @Test
    public void testJwtTokenWithNullEmail() {
        /* this will return null as there are no object exists with email <null> */
        Mockito.when(infoProcessingAPI.getUserInfo(null)).thenReturn(null);
        CompletableFuture<String> jwtToken = jwtCreateImpl.loginUser(getUser());
        /* response of NO_USER_EMAIL should be checked here */
        Assert.assertEquals("NO_USER_EMAIL",jwtToken);
    }

    /*TODO */

    /* similarly you need to check
    * when password is null <AND>
    * when password doesn't match with requester password <AND>
    * generateToken method should be checked for positive scenrio as well as case scenrio where it will throw
    * UnsupportedEncodingException or JWTCreationException
    * all of these in independant test cases
    */

    private UserInfoJwt getUser(){
        UserInfoJwt userInfoJwt = new UserInfoJwt();
        userInfoJwt.setUserEmail("name@java.com");
        userInfoJwt.setUserEmail("myPassword");
        return userInfoJwt;
    }

    private AppUser getAppUser() {

        AppUser user = new AppUser();
        user.setId(1);
        user.setName("name");
        user.setEmail("appuser@java.com");
        return user;
    }
}
psi
  • 269
  • 2
  • 13
  • I didn't have any idea about Junit and Mocking(how to mock a class and methods) so could you please explain this with code. – kundan gupta Aug 03 '19 at 13:37
  • @kundangupta edited my answer as per your case it should be good to get you started – psi Aug 03 '19 at 14:58