HttpRunner3的变量是如何传递的
HttpRunner3的变量可以在测试类的用例配置中通过variables添加,也可以在测试步骤中使用extract()、with_jmespath()提取出来放到变量x,再用$x传递给下一个接口使用,比如登录到下单流程的部分测试脚本如下:
HttpRunner3的变量可以在测试类的用例配置中通过variables添加,也可以在测试步骤中使用extract()、with_jmespath()提取出来放到变量x,再用$x传递给下一个接口使用,比如登录到下单流程的部分测试脚本如下:
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 Servlet生命周期 Servlet的生命周期由Servlet容器(如Tomcat、Jetty等)管理,主要包括以下5个阶段: 加载Servlet类 创建Servlet实例 调用init方法 调用service方法 调用destroy方法 加载(Loading): 当Servlet容器启动或第一次接收到对某个Servlet的请求时,它会加载Servlet类 这个过程只发生一次,除非Servlet被卸载或容器重新启动 实例化(Instantiation): 在加载Servlet类之后,容器会创建一个Servlet实例 这个实例化过程也是一次性的,除非Servlet被卸载或容器重新启动 初始化(Initialization): 容器调用Servlet实例的init()方法进行初始化 init()方法只被调用一次,用于执行一次性的初始化任务,如读取配置参数、初始化资源等 你可以重写init()方法以执行自定义的初始化逻辑 public void init(ServletConfig config) 请求处理(Request Handling): 每当有请求到达时,容器会调用Servlet的service()方法来处理请求 service()方法根据请求的类型(如GET、POST等)调用相应的处理方法(如doGet()、doPost()等) public void service(ServletRequest request, ServletResponse response) 销毁(Destruction): 当容器决定卸载Servlet(如容器关闭或Servlet被重新加载)时,它会调用Servlet的destroy()方法 destroy()方法用于执行清理任务,如关闭资源、保存状态等 destroy()方法只被调用一次 public void destroy() Servlet重新加载 Servlet被重新加载通常发生在以下几种情况下: Servlet类文件被修改: 如果在开发过程中修改了Servlet类文件,Servlet容器可能会检测到这些更改并重新加载Servlet 这通常发生在开发环境中,生产环境中一般不会自动重新加载 容器配置发生变化: 如果修改了Servlet容器的配置文件(如web.xml),容器可能会重新加载相关的Servlet 容器重启: 当Servlet容器重启时,所有的Servlet都会被重新加载 手动重新加载: 某些Servlet容器提供了手动重新加载Servlet的功能,通常通过管理控制台或命令行工具 当Servlet被重新加载时,Servlet容器会执行以下步骤: 销毁现有的Servlet实例: 容器调用现有Servlet实例的destroy()方法,执行清理任务 释放资源,如关闭数据库连接、释放文件句柄等 卸载Servlet类: 容器卸载现有的Servlet类,释放类加载器持有的资源 重新加载Servlet类: 容器重新加载Servlet类文件,创建新的类加载器实例 实例化新的Servlet对象: 容器创建新的Servlet实例 初始化新的Servlet实例: 容器调用新的Servlet实例的init()方法进行初始化 Servlet代码示例 有3种方式使用Servlet: ①实现Servlet接口 import java.io.*; import javax.servlet.*; public class First implements Servlet { ServletConfig config = null; public void init(ServletConfig config) { this.config = config; System.out.println("servlet is initialized"); } public void service(ServletRequest req, ServletResponse res) throws IOException, ServletException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); out.print("<html><body>"); out.print("<b>hello simple servlet</b>"); out.print("</body></html>"); } public void destroy() { System.out.println("servlet is destroyed"); } public ServletConfig getServletConfig() { return config; } public String getServletInfo() { return "copyright 2007-1010"; } } ②继承GenericServlet类 ...
你可能已经迫不及待想安装Java,写个Java程序跑起来了。但是在这之前,有些概念需要提前了解,因为Java跟C、C++和Python都有点不一样。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 从一个问题说起 对于以下测试脚本: 为了能调用进入房间接口,需要从考场接口获取考场token。为了调用考场接口,需要从登陆接口获取登陆token。元件说明如下: 学生登录,提取登录${token}传入下个接口参数。 添加HTTP Header Manager: 考场token,提取考场${exam_token}传入下个接口参数。 添加HTTP Header Manager: 进入房间 貌似挺合理,HTTP Header Manager会给下方的接口添加请求头,运行结果真的如我们所料么? 运行顺序 在回答这个问题之前,有必要搞懂JMeter元件的运行顺序,它是由2 个维度来决定的:从上往下和元件类型。 从上往下,即目录树从上往下。元件类型,分为3类: 线程组、逻辑控制器。 取样器。 配置元件、前置处理器、定时器、后置处理器、断言、监听器。 它们的运行顺序如下: 配置元件(如果存在) 前置处理器(如果存在) 定时器(如果存在) 取样器(如果存在) 后置处理器(如果存在且取样器的结果不为空) 断言(如果存在且取样器的结果不为空) 监听器(如果存在且取样器的结果不为空) 换句话说,假设我们新建了1个线程,想用这个线程去发请求。 第一步,初始化配置,比如参数化、设置Header、Cookie等,用到配置元件。 第二步,可能需要给线程加点参数,比如用户参数,用到前置处理器。 第三步,在发送请求前可能会等待一段时间,用到定时器。 第四步,发送请求,用到取样器。 第五步,可能需要提取响应数据,比如正则表达式提取器、JMESPath提取器,用到后置处理器。 第六步,验证结果符合预期,用到断言。 第七步,查看请求响应数据和测试结果,用到监听器。 实践指南 对于以下所列元件: JMeter会按以下步骤运行: 线程组(如果有多个线程组可以在测试计划设置是顺序执行还是同时执行) 简单控制器(父节点) HTTP Cookie管理器(配置元件) 用户参数(前置处理器) Synchronizing Timer(定时器) HTTP 请求1(取样器) 正则表达式提取器(后置处理器) 响应断言(断言) HTTP Cookie管理器(配置元件) 用户参数(前置处理器) Synchronizing Timer(定时器) HTTP 请求2(取样器) 正则表达式提取器(后置处理器) 响应断言(断言) HTTP 请求3(取样器) 察看结果树(严格来讲是与第 6 步并行,也就是取样器之后) 作用域 其中有个观察作用域实际效果的关键元件:HTTP请求2,它的前后并没有元件,但是也被作用上了。在JMeter中,同一层级的元件具有相同的作用域! ...
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 Tag JUnit5可以使用@Tag注解给测试类和测试方法打tag,这些tag能用来在执行时进行过滤,它跟group有点类似。 tag应该遵循以下规则: 不能为null或者为空。 不能包含空格。 不能包含ISO控制字符。 不能包含保留字符:, ( ) & | ! 示例代码: import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @Tag("fast") @Tag("model") class TaggingDemo { @Test @Tag("taxes") void testingTaxCalculation() { } } @Tag还可以通过元注解和组合注解,实现自定义注解,参考: https://dongfanger.gitee.io/blog/JUnit/002-JUnit5%E6%B3%A8%E8%A7%A3%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%BC%95.html#id2 Filter 打好了tag后,在执行时可以进行过滤,比如Maven配置: <!-- ... --> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <configuration> <groups>acceptance | !feature-a</groups> <excludedGroups>integration, regression</excludedGroups> </configuration> </plugin> </plugins> </build> <!-- ... --> groups用来指定包含哪些tag,excludedGroups用来指定排除哪些tag。 Order JUnit5默认使用了某种算法来确定test方法的执行顺序。我们可以通过@TestMethodOrder进行自定义,既可以使用内置类,也可以使用实现了MethodOrderer接口的类。 内置类如下: DisplayName 按DisplayName的字母数字顺序 OrderAnnotation 通过@Order注解指定顺序 Random 随机顺序 Alphanumeric 按test方法名和参数列表的字母数字顺序 示例: ...
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 OkHttp是什么 OkHttp是一个HTTP客户端,它不只是简单的发送请求和接收响应,还包含了失败重试、响应缓存等特性功能,并且能支持同步和异步请求。 OkHttp的语法相当简洁,比如Get: OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } 比如Post: public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } 常见用法 Get(同步) private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("https://publicobject.com/helloworld.txt") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0; i < responseHeaders.size(); i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(response.body().string()); } } Get(异步) private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0, size = responseHeaders.size(); i < size; i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(responseBody.string()); } } }); } 访问Header private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") .addHeader("Accept", "application/vnd.github.v3+json") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println("Server: " + response.header("Server")); System.out.println("Date: " + response.header("Date")); System.out.println("Vary: " + response.headers("Vary")); } } Post JSON public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } Post字符串 public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { String postBody = "" + "Releases\n" + "--------\n" + "\n" + " * _1.0_ May 6, 2013\n" + " * _1.1_ June 15, 2013\n" + " * _1.2_ August 11, 2013\n"; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } } Post Streaming public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { return MEDIA_TYPE_MARKDOWN; } @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8("Numbers\n"); sink.writeUtf8("-------\n"); for (int i = 2; i <= 997; i++) { sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i))); } } private String factor(int n) { for (int i = 2; i < n; i++) { int x = n / i; if (x * i == n) return factor(x) + " × " + i; } return Integer.toString(n); } }; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } } Post文件 public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { File file = new File("README.md"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } } Post parameters private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { RequestBody formBody = new FormBody.Builder() .add("search", "Jurassic Park") .build(); Request request = new Request.Builder() .url("https://en.wikipedia.org/w/index.php") .post(formBody) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } } Post multipart /** * The imgur client ID for OkHttp recipes. If you're using imgur for anything other than running * these examples, please request your own client ID! https://api.imgur.com/oauth2 */ private static final String IMGUR_CLIENT_ID = "..."; private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "Square Logo") .addFormDataPart("image", "logo-square.png", RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png"))) .build(); Request request = new Request.Builder() .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID) .url("https://api.imgur.com/3/image") .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } } 解析JSON响应为Java对象 private final OkHttpClient client = new OkHttpClient(); private final Moshi moshi = new Moshi.Builder().build(); private final JsonAdapter<Gist> gistJsonAdapter = moshi.adapter(Gist.class); public void run() throws Exception { Request request = new Request.Builder() .url("https://api.github.com/gists/c2a7c39532239ff261be") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); Gist gist = gistJsonAdapter.fromJson(response.body().source()); for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) { System.out.println(entry.getKey()); System.out.println(entry.getValue().content); } } } static class Gist { Map<String, GistFile> files; } static class GistFile { String content; } 响应缓存 private final OkHttpClient client; public CacheResponse(File cacheDirectory) throws Exception { int cacheSize = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(cacheDirectory, cacheSize); client = new OkHttpClient.Builder() .cache(cache) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); String response1Body; try (Response response1 = client.newCall(request).execute()) { if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1); response1Body = response1.body().string(); System.out.println("Response 1 response: " + response1); System.out.println("Response 1 cache response: " + response1.cacheResponse()); System.out.println("Response 1 network response: " + response1.networkResponse()); } String response2Body; try (Response response2 = client.newCall(request).execute()) { if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2); response2Body = response2.body().string(); System.out.println("Response 2 response: " + response2); System.out.println("Response 2 cache response: " + response2.cacheResponse()); System.out.println("Response 2 network response: " + response2.networkResponse()); } System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); } 取消调用 private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build(); final long startNanos = System.nanoTime(); final Call call = client.newCall(request); // Schedule a job to cancel the call in 1 second. executor.schedule(new Runnable() { @Override public void run() { System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f); call.cancel(); System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f); } }, 1, TimeUnit.SECONDS); System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f); try (Response response = call.execute()) { System.out.printf("%.2f Call was expected to fail, but completed: %s%n", (System.nanoTime() - startNanos) / 1e9f, response); } catch (IOException e) { System.out.printf("%.2f Call failed as expected: %s%n", (System.nanoTime() - startNanos) / 1e9f, e); } } 超时 private final OkHttpClient client; public ConfigureTimeouts() throws Exception { client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build(); try (Response response = client.newCall(request).execute()) { System.out.println("Response completed: " + response); } } Per-call Configuration private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay. .build(); // Copy to customize OkHttp for this request. OkHttpClient client1 = client.newBuilder() .readTimeout(500, TimeUnit.MILLISECONDS) .build(); try (Response response = client1.newCall(request).execute()) { System.out.println("Response 1 succeeded: " + response); } catch (IOException e) { System.out.println("Response 1 failed: " + e); } // Copy to customize OkHttp for this request. OkHttpClient client2 = client.newBuilder() .readTimeout(3000, TimeUnit.MILLISECONDS) .build(); try (Response response = client2.newCall(request).execute()) { System.out.println("Response 2 succeeded: " + response); } catch (IOException e) { System.out.println("Response 2 failed: " + e); } } 处理认证鉴权 private final OkHttpClient client; public Authenticate() { client = new OkHttpClient.Builder() .authenticator(new Authenticator() { @Override public Request authenticate(Route route, Response response) throws IOException { if (response.request().header("Authorization") != null) { return null; // Give up, we've already attempted to authenticate. } System.out.println("Authenticating for response: " + response); System.out.println("Challenges: " + response.challenges()); String credential = Credentials.basic("jesse", "password1"); return response.request().newBuilder() .header("Authorization", credential) .build(); } }) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/secrets/hellosecret.txt") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } } 跳过重试: ...
可以通过命令行查看所有marker,包括内置和自定义的
数学里面的加减乘除,就是运算符,但是 Python 的运算符更多样,更复杂,分为算术运算符、比较运算符、赋值运算符、位运算符、逻辑运算符、成员运算符、身份运算符。为了更直观的看到运算符的使用,本文采用代码和注释结合的方式进行讲解。
这两天要在阿里云日志中操作UI,以输入关键字搜索日志。
Spring Boot helps you to create stand-alone, production-grade Spring-based applications that you can run. Most Spring Boot applications need very little Spring configuration.