'How to deal with Mock and InjectMock
Let's say I have this class (omitted some parts for brevity):
package com.bitbank.config;
@Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = -2338626292552177485L;
public static final long JWT_TOKEN_VALIDITY = 5L * 60 * 60;
@Value("${jwt.secret}")
private String secret;
@Autowired
private TimeSource timeSource;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
// while creating the token -
// 1. Define claims of the token, like Issuer, Expiration, Subject, and the ID
// 2. Sign the JWT using the HS512 algorithm and secret key.
// 3. According to JWS Compact
// Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
// compaction of the JWT to a URL-safe string
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(timeSource.getCurrentTimeMillis()))
.setExpiration(new Date(timeSource.getCurrentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, secret).compact();
}
}
To test the expiring of Token, I created another class:
package com.bitbank.utils;
import org.springframework.stereotype.Component;
@Component
public class TimeSource {
public Long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
}
So, I could inject fake / old millis and test that token is expired.
This is my class test:
@SpringBootTest
@TestPropertySource("classpath:application.properties")
class JwtTokenUtilTest {
@Mock
private TimeSource timeSource;
@InjectMocks
private JwtTokenUtil jwtTokenUtil;
@Test
void canCheckIsExpired() {
when(timeSource.getCurrentTimeMillis()).thenReturn(100L);
UserDetails userDetails = new User("username", "password", new ArrayList<>());
String token = jwtTokenUtil.generateToken(userDetails);
assertFalse(jwtTokenUtil.validateToken(token, userDetails));
}
}
But I have several issues with it.
With this mode (@Mock and @InjectMocks) I have error:
base64-encoded secret key cannot be null or empty.`
I know because class itself it is Mocked, so cannot read the application.properties in test folder.
If I use @Autowired:
@SpringBootTest
@TestPropertySource("classpath:application.properties")
class JwtTokenUtilTest {
@Mock
private TimeSource timeSource;
@Autowired
private JwtTokenUtil jwtTokenUtil;
The test itself fails. Of course, it seems that it didn't inject the 100L millis.
If I swap class:
@Autowired
private TimeSource timeSource;
@InjectMocks
private JwtTokenUtil jwtTokenUtil;
I get:
Cannot invoke "com.bitbank.utils.TimeSource.getCurrentTimeMillis()" because "this.timeSource" is null
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
