简体   繁体   English

从jar动态加载步骤定义文件

[英]Dynamically load step definition file from jar

I have a Gherkin executor where I execute my feature files. 我有一个Gherkin执行器,可以在其中执行功能文件。 What I would like to do would be to add a StepDefinition file from an other jar. 我想做的是从另一个jar添加一个StepDefinition文件。 The user would be able to use my project with the step def that I have already wrote but he would also be able to add custom definitions from his own jar file. 用户可以使用我已经编写的step def使用我的项目,但他也可以从自己的jar文件中添加自定义定义。

Currently I have a JavaClassLoader where I load my class from my jar and I use it in my main 目前,我有一个JavaClassLoader,可从jar中加载类,并在主目录中使用它

public class JavaClassLoader<C> extends ClassLoader {

public C LoadClass(String directory, String classpath, Class<C> parentClass) throws ClassNotFoundException {
    File pluginsDir = new File(System.getProperty("user.dir") + directory);
    for (File jar : pluginsDir.listFiles()) {
      try {
        ClassLoader loader = URLClassLoader.newInstance(
            new URL[] { jar.toURL() },
            getClass().getClassLoader()
        );
        Class<?> clazz = Class.forName(classpath, true, loader);
        Class<? extends C> newClass = clazz.asSubclass(parentClass);
        // Apparently its bad to use Class.newInstance, so we use 
        // newClass.getConstructor() instead
        Constructor<? extends C> constructor = newClass.getConstructor();
        return constructor.newInstance();

      } catch (ClassNotFoundException e) {
        // There might be multiple JARs in the directory,
        // so keep looking
        continue;
      } catch (MalformedURLException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InstantiationException e) {
        e.printStackTrace();
      }
    }
    throw new ClassNotFoundException("Class " + classpath
        + " wasn't found in directory " + System.getProperty("user.dir") + directory);
  }

} }

JavaClassLoader<AbstractStepDefs> loader = new JavaClassLoader<AbstractStepDefs>();  
    loader.LoadClass("/", "stepDef.dynamicClass", AbstractStepDefs.class);  

The problem is that Cucumber isn't able to read the methods that I wrote in my other jar. 问题在于Cucumber无法读取我在另一个jar中编写的方法。 Is there a way to use a step def file that isn't in the project? 有没有办法使用项目中没有的step def文件?

Is there a way to use a step def file that isn't in the project? 有没有办法使用项目中没有的step def文件?

Yes, and no. 是的,没有。 The yes part is closer to "sort of". 是的部分更接近“排序”。 git supports a couple of ways of referencing subprojects within other projects. git支持在其他项目中引用子项目的几种方法。 The common "subprojects" are maintained in their own project and then pulled into using projects. 常见的“子项目”保留在自己的项目中,然后拉入使用项目。 Look here for a discussion. 在这里寻找讨论。 I looked into doing submodules once. 我曾经考虑做一次子模块。 I even had it working. 我什至让它工作了。 But I couldn't convince the TeamCity owners to support it. 但是我无法说服TeamCity所有者支持它。 It works but you have to be careful about how you use it. 它可以工作,但是您必须谨慎使用它。 There are haters . 仇恨者

What I ended up doing was to create a shared "global" project that contained page files for the common login and navigation pages. 我最终要做的是创建一个共享的“全局”项目,其中包含常见登录页面和导航页面的页面文件。 This global project also contained all the startup and shutdown support for different browsers and for remote execution on SauceLabs. 该全局项目还包含对不同浏览器以及SauceLabs上远程执行的所有启动和关闭支持。

The step definitions had to be repeated (yuck; I prefer DRY ) but these are small as they mostly just call the page file methods. 必须重复步骤定义(糟糕,我更喜欢DRY ),但是它们很小,因为它们大多只是调用页面文件方法。 All of these web pages are defined in the global project in their own class files. 所有这些网页都在全局项目中的自己的类文件中定义。 The common housekeeping code is defined in class WebDriverManager. 常见的客房清洁代码在WebDriverManager类中定义。

@Given("^I navigate to the public ACME WebPage and select Login$")
public void iNavigateToTheAcmePublicWebPage() {
    pageFactory.AcmePublicWebPage().navigateTo(
      WebDriverManager.instance().getAcmeUrl());

    pageFactory.AcmePublicWebPage().closeNotificationPopUp(); //If there is one
    pageFactory.AcmePublicWebPage().selectLoginLink();
}

@When("^I close the browser$")
public void iCloseTheBrowser() {
    WebDriverManager.instance().closeBrowser();
}

I have reduced most, but not all duplication. 我减少了大部分但不是全部重复。 Most junior test automation engineers don't have to worry about the heavy lifting as long as I maintain the global git project and notify them when they need to download a new global jar from TeamCity. 只要我维护全局git项目并在需要从TeamCity下载新的全局jar时通知他们,大多数初级测试自动化工程师就不必担心繁重的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM