在 TestNG 中将 SoftAssert 与并行执行结合使用会产生意想不到的结果
Using SoftAssert with Parallel Execution in TestNG produces unexpected results
我正在使用 rest-assured library to test our REST api that deals with data on sports. In short I have 2 different @Test methods to call per sport, one @Test method to make multiple GET requests to gather all athlete image urls and store in a static ArrayList, and the other method to instantiate a SoftAssert 对象,实际上在 for 循环中调用所有 url,并软断言 200 响应代码。然后我在第二个测试方法的末尾做一个 assertAll()。
例如-我有一个@Test getSoccerAthletes() 从响应中收集所有 urls,由于响应有限,该方法将重复直到所有运动员 urls 被收集一次 250 名运动员。在这个方法完成后,将执行 Soccer 的第二个 @Test 方法,它被命名为 testSoccerAthletes() 并且你可以看到它使用了 dependsOnMethods。下面是设置。
@Test(priority = 1)
public static void getSoccerAthletes() {
baseURI = "https://XXXXX";
basePath = "XXXXX";
Response res = given().queryParam("apikey", "XXXXXXXX")
.queryParam("top", "250")
.queryParam("skip", soccerSkip)
.when().get();
Assert.assertEquals(res.statusCode(), 200);
JsonPath jPath = res.jsonPath();
System.out.println("Soccer: currentPageStart/totalCount " + jPath.getInt("currentPageStart")
+ "/" + jPath.getInt("totalCount"));
if (soccerSkip == 0) {
allSoccerAthletes = jPath.get("page.links.headshots.full");
} else {
ArrayList<String> athletes = jPath.get("page.links.headshots.full");
allSoccerAthletes.addAll(athletes);
}
if (jPath.getInt("currentPageStart") + 250 < jPath.getInt("totalCount")) {
soccerSkip += 250;
getSoccerAthletes();
}
}
@Test(priority = 2, dependsOnMethods = {"getSoccerAthletes"})
public static void testSoccerAthletes() {
SoftAssert softAssert = new SoftAssert();
for (int i = 0; i < allSoccerAthletes.size(); i++) {
String url = allSoccerAthletes.get(i);
System.out.println("Soccer Athlete: " + i + "/" + allSoccerAthletes.size());
Response res = when().head(url);
softAssert.assertEquals(res.statusCode(), 200, "Failed url: " + url);
if (i == allSoccerAthletes.size() - 1)
allSoccerAthletes.clear();
}
softAssert.assertAll();
}
我看到了不同的结果,其中一些因 @Test testXXXXAthletes 方法的失败而混淆。在线的第一个建议是在每个 @Test 方法(我目前为每个 testXXXXAthletes 方法)中实例化一个 SoftAssert 对象,所以不可能。
我开始倾向于线程安全问题,但我不确定如何推进解决方案。我认为存在线程安全问题的原因来自我研究过的一些文章,但并不完全理解。文章 -->
https://learn2automate.wordpress.com/2017/07/13/parallel-testng-soft-assertions-the-right-way/,
Retrieve test name on TestNG,
https://github.com/rest-assured/rest-assured/issues/1420
如果能帮助解决我的问题,我们将不胜感激!顺便说一句,我还研究了使用 @DataProvider 注释,这让我想到了有关这些测试结构的其他问题。 getXXXAthletes 方法充当 testXXXAthletes 方法的数据提供者,但它们具有 dependsOnMethods 属性。我应该同时使用 DataProvider 和 dependsOnMethods,还是应该同时使用另一个?
进一步的研究证实了我关于 thread-safety 问题的理论。我能够得出结论,该问题与 SoftAssert 无关,而与 rest-assured 而非 thread-safe 有关。该信息可以在这里找到 --> https://github.com/rest-assured/rest-assured/pull/851
我找到了一个 thread-local 分支,其中有人好心地完成了 rest-assured thread-safe 的工作。我下载了 2 个文件 RestAssuredThreadLocal 和 RestAssuredThreadLocalImpl 可以在这里看到 --> https://github.com/rest-assured/rest-assured/commit/3307ba6c79c5547e88cea286d38e5c8a6d679229
下载这 2 个文件后,有一些错误需要解决,一些已弃用的方法需要更换。之后,我能够成功地 运行 我的 rest-assured 测试与 TestNG 并行并获得正确的结果。
我正在使用 rest-assured library to test our REST api that deals with data on sports. In short I have 2 different @Test methods to call per sport, one @Test method to make multiple GET requests to gather all athlete image urls and store in a static ArrayList, and the other method to instantiate a SoftAssert 对象,实际上在 for 循环中调用所有 url,并软断言 200 响应代码。然后我在第二个测试方法的末尾做一个 assertAll()。
例如-我有一个@Test getSoccerAthletes() 从响应中收集所有 urls,由于响应有限,该方法将重复直到所有运动员 urls 被收集一次 250 名运动员。在这个方法完成后,将执行 Soccer 的第二个 @Test 方法,它被命名为 testSoccerAthletes() 并且你可以看到它使用了 dependsOnMethods。下面是设置。
@Test(priority = 1)
public static void getSoccerAthletes() {
baseURI = "https://XXXXX";
basePath = "XXXXX";
Response res = given().queryParam("apikey", "XXXXXXXX")
.queryParam("top", "250")
.queryParam("skip", soccerSkip)
.when().get();
Assert.assertEquals(res.statusCode(), 200);
JsonPath jPath = res.jsonPath();
System.out.println("Soccer: currentPageStart/totalCount " + jPath.getInt("currentPageStart")
+ "/" + jPath.getInt("totalCount"));
if (soccerSkip == 0) {
allSoccerAthletes = jPath.get("page.links.headshots.full");
} else {
ArrayList<String> athletes = jPath.get("page.links.headshots.full");
allSoccerAthletes.addAll(athletes);
}
if (jPath.getInt("currentPageStart") + 250 < jPath.getInt("totalCount")) {
soccerSkip += 250;
getSoccerAthletes();
}
}
@Test(priority = 2, dependsOnMethods = {"getSoccerAthletes"})
public static void testSoccerAthletes() {
SoftAssert softAssert = new SoftAssert();
for (int i = 0; i < allSoccerAthletes.size(); i++) {
String url = allSoccerAthletes.get(i);
System.out.println("Soccer Athlete: " + i + "/" + allSoccerAthletes.size());
Response res = when().head(url);
softAssert.assertEquals(res.statusCode(), 200, "Failed url: " + url);
if (i == allSoccerAthletes.size() - 1)
allSoccerAthletes.clear();
}
softAssert.assertAll();
}
我看到了不同的结果,其中一些因 @Test testXXXXAthletes 方法的失败而混淆。在线的第一个建议是在每个 @Test 方法(我目前为每个 testXXXXAthletes 方法)中实例化一个 SoftAssert 对象,所以不可能。
我开始倾向于线程安全问题,但我不确定如何推进解决方案。我认为存在线程安全问题的原因来自我研究过的一些文章,但并不完全理解。文章 --> https://learn2automate.wordpress.com/2017/07/13/parallel-testng-soft-assertions-the-right-way/, Retrieve test name on TestNG, https://github.com/rest-assured/rest-assured/issues/1420
如果能帮助解决我的问题,我们将不胜感激!顺便说一句,我还研究了使用 @DataProvider 注释,这让我想到了有关这些测试结构的其他问题。 getXXXAthletes 方法充当 testXXXAthletes 方法的数据提供者,但它们具有 dependsOnMethods 属性。我应该同时使用 DataProvider 和 dependsOnMethods,还是应该同时使用另一个?
进一步的研究证实了我关于 thread-safety 问题的理论。我能够得出结论,该问题与 SoftAssert 无关,而与 rest-assured 而非 thread-safe 有关。该信息可以在这里找到 --> https://github.com/rest-assured/rest-assured/pull/851
我找到了一个 thread-local 分支,其中有人好心地完成了 rest-assured thread-safe 的工作。我下载了 2 个文件 RestAssuredThreadLocal 和 RestAssuredThreadLocalImpl 可以在这里看到 --> https://github.com/rest-assured/rest-assured/commit/3307ba6c79c5547e88cea286d38e5c8a6d679229
下载这 2 个文件后,有一些错误需要解决,一些已弃用的方法需要更换。之后,我能够成功地 运行 我的 rest-assured 测试与 TestNG 并行并获得正确的结果。