为 appium 测试脚本创建独立的 jar
Create stand-alone jar for appium test scripts
我想为 Appium 测试脚本创建一个不依赖的独立(瘦 jar)jar。
我有一个亚军class
import org.junit.runner.JUnitCore;
import java.net.MalformedURLException;
public class Runner {
public static void main(String[] args) throws MalformedURLException {
try{
JUnitCore.runClasses(Calculator.class);
}finally {
}
}
}
和
我有一个计算器测试 class
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
//import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class Calculator {
// WebDriver driver;
public AndroidDriver<MobileElement> driver;
@Before
public void setUp() throws MalformedURLException{
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("udid", "ZH33L2Z6KL"); //Give Device ID of your mobile phone
caps.setCapability("platformName", "Android");
caps.setCapability("platformVersion", "6.0.1");
caps.setCapability("automationName", "uiautomator2");
caps.setCapability("skipUnlock","true");
caps.setCapability("appPackage", "com.google.android.calculator");
caps.setCapability("appActivity", "com.android.calculator2.Calculator");
caps.setCapability("noReset","true");
driver = new AndroidDriver<MobileElement>(new URL("http://127.0.0.1:4723/wd/hub"), caps);
}
@Test
public void testCal() throws Exception {
//locate the Text on the calculator by using By.name()
WebElement two=driver.findElement(By.id("digit_2"));
two.click();
WebElement plus=driver.findElement(By.id("op_add"));
plus.click();
WebElement four=driver.findElement(By.id("digit_4"));
four.click();
WebElement equalTo=driver.findElement(By.id("eq"));
equalTo.click();
//locate the edit box of the calculator by using By.tagName()
WebElement results=driver.findElement(By.id("result_final"));
//Check the calculated value on the edit box
assert results.getText().equals("6"):"Actual value is : "+results.getText()+" did not match with expected value: 6";
}
@After
public void teardown(){
//close the app
driver.quit();
}
}
我已经阅读了一篇关于 ThinJar 和 hollowJar 的文章。
https://dzone.com/articles/the-skinny-on-fat-thin-hollow-and-uber
问题
- 如何添加 Gradle 任务(在 intellij 中)以按照文章构建 thin jar?
- 如何根据文章添加 Gradle 任务来构建 'Hollow' jar?
- 如果我构建一个 'fat' jar,我的 jar 大小是 18mb。如何构建体积更小的瘦 jar 或薄 jar,并单独保留依赖项?
- 如何运行在不同PC上创建'skinny'或'thin'jar?
以下文章回答了这些问题:
Java 构建自动化第 2 部分:使用 Gradle 创建可执行 jar
https://vocon-it.com/2016/11/15/how-to-build-a-lean-jar-file-with-gradle/
相应的示例代码位于:
https://github.com/oveits/gradle-tutorial-build-executable-jar/releases/tag/v1.0
最终的 build.gradle 文件如下:
group 'io.cloudgrey.appiumpro'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
maven { url "https://jitpack.io" }
mavenCentral()
maven { url "https://repo.maven.apache.org/maven2" }
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'log4j', name: 'log4j', version:'1.2.17'
testCompile group: 'io.appium', name: 'java-client', version: '7.3.0'
testCompile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.13.0'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
testCompile group: 'com.eclipsesource.minimal-json', name: 'minimal-json', version: '0.9.5'
testCompile group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.3.9'
testCompile group: 'org.zeroturnaround', name: 'zt-exec', version: '1.10'
testCompile group: 'me.xdrop', name: 'fuzzywuzzy', version: '1.2.0'
testCompile group: 'io.appium', name: 'mitmproxy-java', version: '1.6.1'
testCompile group: 'com.applitools', name: 'eyes-appium-java4', version: '4.2.1'
testCompile group: 'com.github.testdotai', name: 'classifier-client-java', version: '1.0.0'
testCompile group: 'com.google.guava', name: 'guava', version: '28.1-jre'
}
test {
outputs.upToDateWhen {false}
useJUnit()
testLogging {
exceptionFormat = 'full'
showStandardStreams = true
}
maxParallelForks = 3
forkEvery = 1
}
task copyJarsToLib (type: Copy) {
def toDir = "build/libs/dependency-jars"
// create directories, if not already done:
file(toDir).mkdirs()
// copy jars to lib folder:
from configurations.compile
into toDir
}
task marshallClasspathDeps(type: Copy) {
from sourceSets.test.runtimeClasspath
// if you need this from the dependencies in the build.gradle then it should be :
// from sourceSets.main.runtimeClasspath
include '**/*.class'
include '**/*.jar'
exclude { FileTreeElement details ->
details.file.name.contains('Edition') || details.file.name.contains('kotlin')
}
into 'build/libs/dependency-jars'
}
build.dependsOn(marshallClasspathDeps)
task buildJar(dependsOn:classes,type: Jar) {
// exclude log properties (recommended)
exclude ("log4j.properties")
// make jar executable: see
manifest {
attributes (
'Main-Class': 'com.example.appium.Runner',
// add classpath to Manifest; see
"Class-Path": '. dependency-jars/' + sourceSets.test.runtimeClasspath.collect { it.getName() }.join(' dependency-jars/')
)
}
baseName = "AppiumTests"
from sourceSets.test.output
include 'com/example/appium/*.class'
}
// always call copyJarsToLib when building jars:
jar.dependsOn copyJarsToLib
build.dependsOn(buildJar)
// END AUTOMATICALLY INSERTED
可以使用以下方式执行测试用例:
java -jar -Dlog4j.configuration=file:%cd%\log4j.properties build\libs\AppiumTests.jar
您 link 中使用的术语有点奇怪。使用 gradle,总是构建“瘦”jar。它是默认工件,检查 build/libs 文件夹。如果您应用应用程序插件,则在 build/distribution 下也会构建一个分发 zip,它几乎是 fat jar(它是所有相关 jar 的 zip)。但根据定义,您不能将胖 jar 构建成更小的尺寸,也不能简单地 运行 目标主机上的“瘦”或“瘦”jar。
运行 您的应用程序始终只需要三样东西:
你的代码的编译工件 - 一堆 .class 文件对应于,并且只对应于你编写的代码,通常以 jar 格式打包。这是那个术语中的瘦罐子。如果您不做任何特别的事情,这也是从构建(任何构建系统、maven、gradle 等)中产生的最常见的工件。
库依赖项 - 所有第 3 方 jar
运行时间 - 这个通常指的是Java本身。
以上所有内容都需要出现在您即将 运行 您的应用程序的主机上。现在,变得有点复杂的是您实际需要 ship 到该主机的东西(这称为部署):
- 显然你需要1号寄给主机
- 通常你会expect/assume主机上预装3号
第2个第3方依赖呢?答案是取决于.
如果可以在目标上预安装(其中一些)这些依赖项
楼主,不用寄。在这种情况下,通常人们会
只需将这些依赖项也称为“运行时间”。例如,
Maven是运行时代,也是Gradle时代。这些本身就是 Java
当你写一个 Maven/Gradle 插件时给你的库。你
通常会期望使用您的代码的人拥有 maven/gradle
已经安装了。他们 运行 通过 maven/gradle 您的代码,并且
maven/gradle 将 提供 您的代码所需的依赖项
当运行宁它。这就是为什么在 Maven 中这种依赖关系是
称为“提供”。 Maven 有专门的依赖范围。
如果目标主机上没有提供您的任何依赖项,您
需要发货,期间。
在Gradle中,如果你应用应用程序插件(它会自动应用分发插件),你可以同时拥有你的工件和你的依赖项(不包括java 运行时间) 在单个 zip 中 - 这称为分发。
plugins {
id 'java'
id 'application'
}
构建后,您会在 build/distributions 下找到一个 zip 文件。解压后有两个文件夹:bin 和 lib。 在 lib 文件夹中有您的 jar 和所有依赖项 jar。这在技术上不是一个胖罐子,因为它不是一个单一的罐子。但 jar-or-not 只是一种格式。最终,您所追求的只是将您的代码和依赖项传送到目标主机。分发 zip 不会与 jar 混淆,因为 jar 合并不像文件夹合并那么简单。相反,分发 zip 希望您在目标主机上解压缩并调用 bin 文件夹下的脚本来启动应用程序。
我想为 Appium 测试脚本创建一个不依赖的独立(瘦 jar)jar。
我有一个亚军class
import org.junit.runner.JUnitCore;
import java.net.MalformedURLException;
public class Runner {
public static void main(String[] args) throws MalformedURLException {
try{
JUnitCore.runClasses(Calculator.class);
}finally {
}
}
}
和 我有一个计算器测试 class
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
//import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class Calculator {
// WebDriver driver;
public AndroidDriver<MobileElement> driver;
@Before
public void setUp() throws MalformedURLException{
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("udid", "ZH33L2Z6KL"); //Give Device ID of your mobile phone
caps.setCapability("platformName", "Android");
caps.setCapability("platformVersion", "6.0.1");
caps.setCapability("automationName", "uiautomator2");
caps.setCapability("skipUnlock","true");
caps.setCapability("appPackage", "com.google.android.calculator");
caps.setCapability("appActivity", "com.android.calculator2.Calculator");
caps.setCapability("noReset","true");
driver = new AndroidDriver<MobileElement>(new URL("http://127.0.0.1:4723/wd/hub"), caps);
}
@Test
public void testCal() throws Exception {
//locate the Text on the calculator by using By.name()
WebElement two=driver.findElement(By.id("digit_2"));
two.click();
WebElement plus=driver.findElement(By.id("op_add"));
plus.click();
WebElement four=driver.findElement(By.id("digit_4"));
four.click();
WebElement equalTo=driver.findElement(By.id("eq"));
equalTo.click();
//locate the edit box of the calculator by using By.tagName()
WebElement results=driver.findElement(By.id("result_final"));
//Check the calculated value on the edit box
assert results.getText().equals("6"):"Actual value is : "+results.getText()+" did not match with expected value: 6";
}
@After
public void teardown(){
//close the app
driver.quit();
}
}
我已经阅读了一篇关于 ThinJar 和 hollowJar 的文章。
https://dzone.com/articles/the-skinny-on-fat-thin-hollow-and-uber
问题
- 如何添加 Gradle 任务(在 intellij 中)以按照文章构建 thin jar?
- 如何根据文章添加 Gradle 任务来构建 'Hollow' jar?
- 如果我构建一个 'fat' jar,我的 jar 大小是 18mb。如何构建体积更小的瘦 jar 或薄 jar,并单独保留依赖项?
- 如何运行在不同PC上创建'skinny'或'thin'jar?
以下文章回答了这些问题: Java 构建自动化第 2 部分:使用 Gradle 创建可执行 jar https://vocon-it.com/2016/11/15/how-to-build-a-lean-jar-file-with-gradle/
相应的示例代码位于: https://github.com/oveits/gradle-tutorial-build-executable-jar/releases/tag/v1.0
最终的 build.gradle 文件如下:
group 'io.cloudgrey.appiumpro'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
maven { url "https://jitpack.io" }
mavenCentral()
maven { url "https://repo.maven.apache.org/maven2" }
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'log4j', name: 'log4j', version:'1.2.17'
testCompile group: 'io.appium', name: 'java-client', version: '7.3.0'
testCompile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.13.0'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
testCompile group: 'com.eclipsesource.minimal-json', name: 'minimal-json', version: '0.9.5'
testCompile group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.3.9'
testCompile group: 'org.zeroturnaround', name: 'zt-exec', version: '1.10'
testCompile group: 'me.xdrop', name: 'fuzzywuzzy', version: '1.2.0'
testCompile group: 'io.appium', name: 'mitmproxy-java', version: '1.6.1'
testCompile group: 'com.applitools', name: 'eyes-appium-java4', version: '4.2.1'
testCompile group: 'com.github.testdotai', name: 'classifier-client-java', version: '1.0.0'
testCompile group: 'com.google.guava', name: 'guava', version: '28.1-jre'
}
test {
outputs.upToDateWhen {false}
useJUnit()
testLogging {
exceptionFormat = 'full'
showStandardStreams = true
}
maxParallelForks = 3
forkEvery = 1
}
task copyJarsToLib (type: Copy) {
def toDir = "build/libs/dependency-jars"
// create directories, if not already done:
file(toDir).mkdirs()
// copy jars to lib folder:
from configurations.compile
into toDir
}
task marshallClasspathDeps(type: Copy) {
from sourceSets.test.runtimeClasspath
// if you need this from the dependencies in the build.gradle then it should be :
// from sourceSets.main.runtimeClasspath
include '**/*.class'
include '**/*.jar'
exclude { FileTreeElement details ->
details.file.name.contains('Edition') || details.file.name.contains('kotlin')
}
into 'build/libs/dependency-jars'
}
build.dependsOn(marshallClasspathDeps)
task buildJar(dependsOn:classes,type: Jar) {
// exclude log properties (recommended)
exclude ("log4j.properties")
// make jar executable: see
manifest {
attributes (
'Main-Class': 'com.example.appium.Runner',
// add classpath to Manifest; see
"Class-Path": '. dependency-jars/' + sourceSets.test.runtimeClasspath.collect { it.getName() }.join(' dependency-jars/')
)
}
baseName = "AppiumTests"
from sourceSets.test.output
include 'com/example/appium/*.class'
}
// always call copyJarsToLib when building jars:
jar.dependsOn copyJarsToLib
build.dependsOn(buildJar)
// END AUTOMATICALLY INSERTED
可以使用以下方式执行测试用例:
java -jar -Dlog4j.configuration=file:%cd%\log4j.properties build\libs\AppiumTests.jar
您 link 中使用的术语有点奇怪。使用 gradle,总是构建“瘦”jar。它是默认工件,检查 build/libs 文件夹。如果您应用应用程序插件,则在 build/distribution 下也会构建一个分发 zip,它几乎是 fat jar(它是所有相关 jar 的 zip)。但根据定义,您不能将胖 jar 构建成更小的尺寸,也不能简单地 运行 目标主机上的“瘦”或“瘦”jar。
运行 您的应用程序始终只需要三样东西:
你的代码的编译工件 - 一堆 .class 文件对应于,并且只对应于你编写的代码,通常以 jar 格式打包。这是那个术语中的瘦罐子。如果您不做任何特别的事情,这也是从构建(任何构建系统、maven、gradle 等)中产生的最常见的工件。
库依赖项 - 所有第 3 方 jar
运行时间 - 这个通常指的是Java本身。
以上所有内容都需要出现在您即将 运行 您的应用程序的主机上。现在,变得有点复杂的是您实际需要 ship 到该主机的东西(这称为部署):
- 显然你需要1号寄给主机
- 通常你会expect/assume主机上预装3号
第2个第3方依赖呢?答案是取决于.
如果可以在目标上预安装(其中一些)这些依赖项 楼主,不用寄。在这种情况下,通常人们会 只需将这些依赖项也称为“运行时间”。例如, Maven是运行时代,也是Gradle时代。这些本身就是 Java 当你写一个 Maven/Gradle 插件时给你的库。你 通常会期望使用您的代码的人拥有 maven/gradle 已经安装了。他们 运行 通过 maven/gradle 您的代码,并且 maven/gradle 将 提供 您的代码所需的依赖项 当运行宁它。这就是为什么在 Maven 中这种依赖关系是 称为“提供”。 Maven 有专门的依赖范围。
如果目标主机上没有提供您的任何依赖项,您 需要发货,期间。
在Gradle中,如果你应用应用程序插件(它会自动应用分发插件),你可以同时拥有你的工件和你的依赖项(不包括java 运行时间) 在单个 zip 中 - 这称为分发。
plugins {
id 'java'
id 'application'
}
构建后,您会在 build/distributions 下找到一个 zip 文件。解压后有两个文件夹:bin 和 lib。 在 lib 文件夹中有您的 jar 和所有依赖项 jar。这在技术上不是一个胖罐子,因为它不是一个单一的罐子。但 jar-or-not 只是一种格式。最终,您所追求的只是将您的代码和依赖项传送到目标主机。分发 zip 不会与 jar 混淆,因为 jar 合并不像文件夹合并那么简单。相反,分发 zip 希望您在目标主机上解压缩并调用 bin 文件夹下的脚本来启动应用程序。