junit4单元测试

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.idea360</groupId>
<artifactId>junit-demo</artifactId>
<version>1.0.0</version>

<name>junit-demo</name>
<description>junit4 mock测试. 欢迎关注公众号【当我遇上你】</description>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
</project>

过滤器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package cn.idea360.junit.filter;

import cn.idea360.junit.wrapper.ContentCachingRequestWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
* @author cuishiying
*/
@Slf4j
public class LogFilter implements Filter{

private final ObjectMapper objectMapper = new ObjectMapper();

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ContentCachingRequestWrapper request = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 请求头
String header = request.getHeader("blog");
// 整个URL的路径
String requestURL = request.getRequestURL().toString();
// 上下文路径(工程名)
String contextPath = request.getContextPath();
// 除去host和工程名部分的路径
String servletPath = request.getServletPath();
// 除去host部分的路径
String requestURI = request.getRequestURI();
// 请求类型
String method = request.getMethod();
// urlParams, 即?后的字符串则为其请求参数,并以&作为分隔符
String queryString = request.getQueryString();
// 默认content-type为application/x-www-form-urlencoded, 参数会以Form Data的形式进行传递,不会显式出现在请求url中
Map<String, String[]> parameterMap = request.getParameterMap();
// 请求体
String body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
log.info(body);
filterChain.doFilter(request, response);
sendUnauthorizedMessage(response, "验签失败");
}

private void sendUnauthorizedMessage(HttpServletResponse response, String message) {
response.setContentType("application/json;charset=UTF-8");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

try {
PrintWriter out = response.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("code", HttpServletResponse.SC_UNAUTHORIZED);
map.put("msg", message);
out.write(objectMapper.writeValueAsString(map));
out.flush();
out.close();
} catch (Exception e) {
log.error("can't push signature err message", e);
}
}
}

ServletInputStream抽象类实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package cn.idea360.junit.delegate;

import org.junit.Assert;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* @see org.springframework.mock.web.DelegatingServletInputStream
*
* @author cuishiying
*/
public class DelegatingServletInputStream extends ServletInputStream {

private final InputStream sourceStream;

private boolean finished = false;


/**
* Create a DelegatingServletInputStream for the given source stream.
* @param sourceStream the source stream (never {@code null})
*/
public DelegatingServletInputStream(InputStream sourceStream) {
Assert.assertNotNull("Source InputStream must not be null", sourceStream);
this.sourceStream = sourceStream;
}

/**
* Return the underlying source stream (never {@code null}).
*/
public final InputStream getSourceStream() {
return this.sourceStream;
}


@Override
public int read() throws IOException {
int data = this.sourceStream.read();
if (data == -1) {
this.finished = true;
}
return data;
}

@Override
public int available() throws IOException {
return this.sourceStream.available();
}

@Override
public void close() throws IOException {
super.close();
this.sourceStream.close();
}

@Override
public boolean isFinished() {
return this.finished;
}

@Override
public boolean isReady() {
return true;
}

@Override
public void setReadListener(ReadListener readListener) {
throw new UnsupportedOperationException();
}

}

流重复消费处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package cn.idea360.junit.wrapper;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
* @author cuishiying
*/
public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {

private final byte[] buffer;

public ContentCachingRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
InputStream is = request.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int read;
while ((read = is.read(buff)) > 0) {
baos.write(buff, 0, read);
}
this.buffer = baos.toByteArray();
}

@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
return new ServletInputStream() {

@Override
public boolean isFinished() {
return false;
}

@Override
public boolean isReady() {
return false;
}

@Override
public void setReadListener(ReadListener readListener) {
// document why this method is empty
}

@Override
public int read() {
return bais.read();
}
};
}

@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}

Mock测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package cn.idea360.junit.filter;

import cn.idea360.junit.delegate.DelegatingServletInputStream;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;

import static org.mockito.Mockito.*;

@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class LogFilterTest {

private StringWriter writer;

@Before
public void setUp() throws Exception {
writer = new StringWriter();
}

@Test
public void logFilter() throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);

String requestBody = "{\"msg\": \"Hello World\"}";

when(request.getHeader("blog")).thenReturn("idea360.cn");
when(request.getMethod()).thenReturn("POST");
when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/junit-demo/sign"));
when(request.getContextPath()).thenReturn("/junit-demo");
when(request.getServletPath()).thenReturn("/sign");
when(request.getRequestURI()).thenReturn("/junit-demo/sign");
when(request.getCharacterEncoding()).thenReturn(StandardCharsets.UTF_8.name());
when(request.getContentType()).thenReturn("application/json");
when(request.getParameter("age")).thenReturn("17");
when(request.getQueryString()).thenReturn("name=admin");
when(request.getInputStream()).thenReturn(new DelegatingServletInputStream(new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8))));

when(response.getWriter()).thenReturn(new PrintWriter(writer));

LogFilter filter = new LogFilter();
filter.doFilter(request, response, filterChain);

Assert.assertEquals("{\"msg\":\"验签失败\",\"code\":401}", writer.toString());
}
}