我正在使用Spring Boot 2.0.1为混合应用创建一个Appium测试框架,而在使用Spring的TestExecutionListeners时遇到了麻烦。
目标:为每个标记有JUnit AppiumDriver<WebElement>
的测试初始化一个新的@Test
实例,并在每次测试后使用AppiumDriver的quit()
退出那些驱动程序实例。>
我的框架的结构:我创建了一个名为TestScope
的自定义范围
public class TestScope implements Scope {
private Map<String, Object> scopedObjects = Collections.synchronizedMap(new HashMap<String, Object>());
private Map<String, Runnable> destructionCallbacks = Collections.synchronizedMap(new HashMap<String, Runnable>());
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!this.scopedObjects.containsKey(name)) {
this.scopedObjects.put(name, objectFactory.getObject());
}
return this.scopedObjects.get(name);
}
@Override
public String getConversationId() {
return null;
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
this.destructionCallbacks.put(name, callback);
}
@Override
public Object remove(String name) {
this.destructionCallbacks.remove(name);
return this.scopedObjects.remove(name);
}
public void reset() {
this.scopedObjects.clear();
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
}
我通过创建应用的配置实例({.1)},并注册TestScope
Bean并为其提供新创建的AppiumDriver<WebElement>
,在应用的配置文件(Application.java)中注册"test"
范围:
@SpringBootApplication
@PropertySource("classpath:application.properties")
public class Application implements EnvironmentAware {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CustomScopeConfigurer customScopeConfigurer() {
CustomScopeConfigurer scopeConfigurer = new CustomScopeConfigurer();
Map<String, Object> scopes = new HashMap<>();
scopes.put("test", this.testScope());
scopeConfigurer.setScopes(scopes);
return scopeConfigurer;
}
@Bean
@Scope("test")
public AppiumDriver<WebElement> driver() {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability(MobileCapabilityType.PLATFORM_NAME, this.env.getProperty("platformName"));
caps.setCapability(MobileCapabilityType.PLATFORM_VERSION, this.env.getProperty("platformVersion"));
caps.setCapability(MobileCapabilityType.DEVICE_NAME, this.env.getProperty("deviceName"));
caps.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT,
Integer.parseInt(this.env.getProperty("newCommandTimeout")));
caps.setCapability(MobileCapabilityType.AUTO_WEBVIEW, true);
// Android Capabilities
if (this.env.getProperty("platformName").equals("Android")) {
caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, this.env.getProperty("androidAppPackage"));
caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, this.env.getProperty("androidAppActivity"));
}
try {
return new AppiumDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"), caps);
} catch (Exception e) {
throw new BeanCreationException("driver", "Failed to create Driver", e);
}
}
@Bean
public TestScope testScope() {
return new TestScope();
}
}
然后,使用正确的配置注释创建我的AbstractTestBase
。我的测试将通过必须从AbstractTestBase
扩展的方式进行,以便它们继承配置,因此他们的测试会为每个测试创建新的AppriumDriver
实例:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = Application.class)
@TestExecutionListeners({ AppiumTestExecutionListener.class, DependencyInjectionTestExecutionListener.class })
public abstract class AbstractTestBase {
@Autowired protected PageObject1 pageObj1;
@Autowired protected PageObject2 pageObj2;
}
最后,在我在AppiumTestExecutionListener
中设置的AbstractTestBase
中,我编写了逻辑以在每次测试前清空TestScope
实例,并在每次测试后退出AppiumDriver实例,这样,当第二次测试调用beforeTestMethod()
时,它清除了TestScope,Spring被迫创建了一个新的驱动程序实例,但是由于某种原因,第一项测试工作正常,而第二项则告诉我该会话是失败的终止。
public class AppiumTestExecutionListener extends AbstractTestExecutionListener {
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
testContext.getApplicationContext().getBean(AppiumDriver.class).quit();
}
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
testContext.getApplicationContext().getBean(TestScope.class).reset();
}
}
不确定是否会发生这种情况,但是似乎当我在页面对象中@Autowire
驱动程序并且第二次测试正在运行时,从不以某种方式重新注入驱动程序实例,以便它们使用新实例?无论如何,我想看看你们是否知道我在设置错误时计算了我在这里要完成的工作。