29. 如何为 JMeter 编写插件¶
Peter Lin 的介绍
不止一次,用户抱怨 JMeter 的开发人员文档已经过时并且不是很有用。为了使开发人员更容易,我决定编写一个简单的分步教程。当我向迈克提到这一点时,他对教程应该涵盖的内容有了一些想法。
在我们深入教程之前,我想说写一个插件并不一定容易,即使对于有几年 Java 经验的人来说也是如此。我为 JMeter 编写的第一个扩展是一个简单的实用程序,用于解析 HTTP 访问日志并生成 XML 格式的请求。它并不是一个真正的插件,因为它是一个独立的命令行实用程序。我的第一个真正的 JMeter 插件是 webservice sampler。我正在开发一个 .NET 项目,需要对 Web 服务进行压力测试。大多数用于测试 .NET Web 服务的商业工具都很糟糕而且成本太高。与其花几百美元买一个蹩脚的测试工具,或者花几千美元买一个好的测试工具,我认为为 JMeter 编写一个插件更容易、更便宜。
经过两周的空闲时间编码后,我有了一个使用 Apache Soap 驱动程序的工作原型。我把它提交给了 JMeter,mike 问我是否想成为一名提交者。我过去曾为 Jakarta JSTL 和 tomcat 贡献过补丁,所以我认为这是一种荣誉。从那时起,我编写了访问日志采样器、Tomcat 5 监视器和分布图。从那时起,Mike 极大地改进了访问日志采样器,并使其更加有用。
Mike Stover 的介绍
我设计 JMeter 的主要目标之一是让编写插件变得容易,以尽可能多地增强 JMeter 的功能。开源的部分好处是很多人可能会努力改进应用程序。我有意识地决定牺牲代码中的一些简单性,让插件编写成为 JMeter 开发人员的一种生活方式。
虽然有些人已经成功地直接挖掘代码并对 JMeter 进行了改进,但一直缺乏关于如何做到这一点的真正教程。我很久以前就尝试写一些关于它的文档,但大多数人认为它没有用。希望在彼得的帮助下,这次尝试会更加成功。
29.1 JMeter的基本结构¶
JMeter 是按协议和功能组织的。这样做是为了让开发人员可以为单个协议构建新的 jar,而无需构建整个应用程序。我们将在本教程的后面部分详细介绍构建 JMeter。由于 JMeter 开发者大多使用 eclipse,本文将使用 eclipse 目录作为参考。
根目录 - /eclipse/workspace/apache-jmeter/
apache-jmeter 里面的文件夹
- 斌
- 包含用于启动 JMeter的.bat和.sh文件。它还包含ApacheJMeter.jar和属性文件
- 构建/文档
- 目录包含 JMeter 文档文件
- 附加功能
- ant 相关的额外文件
- 库
- 包含 JMeter 所需的 jar 文件
- 库/扩展
- 包含 JMeter 的核心 jar 文件和协议
- 源代码
- 包含每个协议和组件的子目录
- src/*/测试
- 单元测试相关目录
- 文档
- 用于文档的 XML 文件。JMeter 从 XML 生成其文档。
随着教程的进行,将提供子目录的解释。现在,让我们关注src目录。
src 里面的文件夹
- 客户端
- 基于 BeanShell 的客户端的代码
- 螺栓
- Bolt 协议的代码
- 组件
- 包含非特定于协议的组件,如可视化工具、断言等。
- 核
- JMeter的核心代码,包括所有核心接口和抽象类。
- 距离
- 构建创建分发的脚本
- 分配检查
- 与测试分布相关的代码。当您想要更新生成的源/二进制存档的内容时,它是查找的地方
- 例子
- 示例采样器演示如何使用新的 bean 框架
- 职能
- 所有组件使用的标准函数
- 发电机
- 生成包含所有元素的测试计划的代码。用于测试分布
- 乔丹
- 提供通用实用程序功能的实用程序类
- 发射器
- 通过 API 帮助启动和停止 JMeter 的代码
- 许可证
- 包含有关 JMeters 依赖项中使用的许可证的信息
- 协议
- 包含 JMeter 支持的不同协议
- 释放
- 与发布 JMeter 发行版相关的代码
- 测试套件
- 用于测试的实用程序代码
- testkit-wiremock
- 使用 WireMock 进行测试的实用程序代码
在协议目录中,是协议特定的组件。
协议 内的文件夹
- ftp
- 用于负载测试 ftp 服务器的组件
- http
- 用于负载测试 Web 服务器的组件
- 爪哇
- 用于负载测试的组件 java 组件
- 数据库
- 使用 JDBC 对数据库服务器进行负载测试的组件
- 杰姆斯
- 用于负载测试 JMS 服务器的组件
- 朱尼特
- 使用 JUnit 测试进行负载测试的组件
- junit 样本
- 基于 JUnit 的测试实现示例
- LDAP
- 用于负载测试 LDAP 服务器的组件
- 邮件
- 负载测试邮件服务器的组件
- 本国的
- 用于负载测试操作系统本机命令的组件
- tcp
- 负载测试 TCP 服务的组件
作为一般规则,所有与 HTTP 相关的采样器都将驻留在http目录中。该规则的例外是 Tomcat5 监视器。它是独立的,因为监视器的功能与压力或功能测试略有不同。它最终可能会被重组,但现在它位于自己的目录中。就难度而言,编写可视化工具可能是最难编写的插件之一。
29.2 JMeter Gui – TestElement 合约¶
在编写任何 JMeter 组件时,您必须了解某些约定——如果 JMeter 组件能够在 JMeter 环境中正常运行,那么它应该如何表现。本节描述了组件的 GUI 部分必须履行的契约。
JMeter 中的 GUI 代码与测试元素代码严格分开。因此,当您编写组件时,将有一个用于测试元素的类,以及另一个用于 GUI 演示的类。GUI 表示类在某种意义上是无状态的,它不应该挂在对测试元素的引用上(尽管有例外)。
GUI 元素应扩展提供的适当抽象类:
- AbstractSamplerGui
- 抽象断言GUI
- AbstractConfigGui
- 抽象控制器GUI
- 抽象后处理器GUI
- 抽象预处理器GUI
- 抽象可视化器
- AbstractTimerGui
这些抽象类为您提供了如此多的管道工作,以至于不扩展它们,而是直接实现接口几乎不是一种选择。如果您迫切需要不扩展这些课程,那么您可以加入 IRC,我可以说服您:-)。
那么,您已经扩展了适当的 GUI 类,还需要做什么?跟着这些步骤:
- 实现getLabelResource()
- 此方法应返回代表组件标题/名称的资源名称。必须将资源输入到 JMeters messages.properties文件中(可能还有翻译)。
- 创建你的图形用户界面。无论你喜欢什么风格,布局你的 GUI。您的课程最终扩展
了JPanel,因此您的布局必须在您的课程自己的ContentPane中。不要通过操作和事件将 GUI 元素连接到您的TestElement类。让 Swing 的内部模型尽可能多地挂在所有数据上。
- 一些标准的 GUI 东西应该添加到所有 JMeter GUI 组件中:
- 为您的班级调用setBorder(makeBorder())。这将给它标准的 JMeter 边框
- 通过makeTitlePanel()添加标题窗格。通常这是添加到 GUI 中的第一件事,应该在 Box 垂直布局方案中完成,或者使用 JMeter 的VerticalLayout
类。这是一个示例init()方法:
private void init() { setLayout(new BorderLayout()); setBorder(makeBorder()); Box box = Box.createVerticalBox(); box.add(makeTitlePanel()); box.add(makeSourcePanel()); add(box,BorderLayout.NORTH); add(makeParameterPanel(),BorderLayout.CENTER); }
- 一些标准的 GUI 东西应该添加到所有 JMeter GUI 组件中:
- 实施公共无效配置(TestElement el)
- 一定要调用super.configure(e)。这将为您填充一些数据,例如元素的名称。
- 使用此方法将数据设置到您的 GUI 元素中。例子:
public void configure(TestElement el) { super.configure(el); useHeaders.setSelected( el.getPropertyAsBoolean(RegexExtractor.USEHEADERS)); useBody.setSelected( !el.getPropertyAsBoolean(RegexExtractor.USEHEADERS)); regexField.setText( el.getPropertyAsString(RegexExtractor.REGEX)); templateField.setText( el.getPropertyAsString(RegexExtractor.TEMPLATE)); defaultField.setText( el.getPropertyAsString(RegexExtractor.DEFAULT)); matchNumberField.setText( el.getPropertyAsString(RegexExtractor.MATCH_NUM)); refNameField.setText( el.getPropertyAsString(RegexExtractor.REFNAME)); }
- 实施public void modifyTestElement(TestElement e)。这是您将数据从 GUI 元素移动到TestElement的地方。这是前一种方法的逻辑逆向。
- 调用super.configureTestElement(e)。这将为您处理一些默认数据。
- 例子:
public void modifyTestElement(TestElement e) { super.configureTestElement(e); e.setProperty(new BooleanProperty( RegexExtractor.USEHEADERS, useHeaders.isSelected())); e.setProperty(RegexExtractor.MATCH_NUMBER, matchNumberField.getText()); if (e instanceof RegexExtractor) { RegexExtractor regex = (RegexExtractor)e; regex.setRefName(refNameField.getText()); regex.setRegex(regexField.getText()); regex.setTemplate(templateField.getText()); regex.setDefaultValue(defaultField.getText()); } }
- 实施公共 TestElement createTestElement()。此方法应创建TestElement类的新实例,然后将其传递给您在上面创建的modifyTestElement(TestElement)
方法
public TestElement createTestElement() { RegexExtractor extractor = new RegexExtractor(); modifyTestElement(extractor); return extractor; }
您不能为您的测试元素保留引用的原因是因为 JMeter 为多个测试元素重用了 GUI 类对象的实例。这样可以节省大量内存。它还使编写新组件的 GUI 部分变得异常容易。您仍然需要为 Swing 中的布局而苦苦挣扎,但您不必担心创建正确的事件和操作以将数据从 GUI 元素获取到TestElement中,这样它可以做一些好事。JMeter 知道何时调用您的 configure 和modifyTestElement方法,您可以在其中以非常直接的方式进行操作。
然而,编写 Visualizers 有点特殊。
29.3 编写可视化工具¶
在组件类型中,可视化器在 Swing 中需要比控制器、函数或采样器等更深入的内容。您可以在components/org/apache/jmeter/visualizers/中找到分布图的完整源代码 。分布图可视化工具分为两类。
- 分布图可视化器
- JMeter 实例化的可视化工具
- 分布图
- 绘制实际图形的 JComponent
编写可视化器的最简单方法是执行以下操作:
- 扩展org.apache.jmeter.visualizers.gui.AbstractVisualizer
- 实现回调和事件通知所需的任何其他接口。例如,DistributionGraphVisualizer实现了以下接口:
- 图像可视化器
- ItemListener – 根据类中的注释, ItemListener已过时,不再使用。
- 图形监听器
- 可清除
AbstractVisualizer提供了一些常用功能,大多数可视化工具(如 Graph Results )都使用这些功能。抽象类提供的通用功能包括:
- 配置测试元素——这意味着它创建一个新的ResultCollector,设置文件并设置错误日志
- 创建股票菜单
- 进行更改时更新测试元素
- 为日志文件创建一个文件面板
- 创建标题面板
在某些情况下,您可能不想显示文件文本框的菜单。在这种情况下,您可以覆盖init()方法。这是DistributionGraphVisualizer的实现。
/** * Initialize the GUI. */ private void init() { this.setLayout(new BorderLayout()); // MAIN PANEL Border margin = new EmptyBorder(10, 10, 5, 10); this.setBorder(margin); // Set up the graph with header, footer, Y axis and graph display JPanel graphPanel = new JPanel(new BorderLayout()); graphPanel.add(createGraphPanel(), BorderLayout.CENTER); graphPanel.add(createGraphInfoPanel(), BorderLayout.SOUTH); // Add the main panel and the graph this.add(makeTitlePanel(), BorderLayout.NORTH); this.add(graphPanel, BorderLayout.CENTER); }
init方法做 的第一件事是创建一个新的BorderLayout。根据您想要布局小部件的方式,您可能需要使用不同的布局管理器。请记住,使用不同的布局管理器是为专家准备的。
init方法做 的第二件事是创建一个边框。如果要增加或减少边框,请更改四个整数值。每个整数值代表像素。如果您希望可视化器没有边框,请跳过第 8 行和第 9 行。第 13 行调用createGraphPanel,它负责配置DistributionGraph并将其添加到可视化器。
private Component createGraphPanel() { graphPanel = new JPanel(); graphPanel.setBorder(BorderFactory.createBevelBorder( BevelBorder.LOWERED,Color.lightGray,Color.darkGray)); graphPanel.add(graph); graphPanel.setBackground(Color.white); return graphPanel; }
在第 5 行,图形组件被添加到图形面板中。构造函数是创建DistributionGraph的新实例的地方。
public DistributionGraphVisualizer() { model = new SamplingStatCalculator("Distribution"); graph = new DistributionGraph(model); graph.setBackground(Color.white); init(); }
DistributionGraphVisualizer 的构造函数负责创建模型和图形。每次完成新结果时,引擎都会通过调用add(SampleResult res)将结果传递给所有侦听器。可视化器将新的SampleResult传递给模型。
public synchronized void add(SampleResult res) { model.addSample(res); updateGui(model.getCurrentSample()); }
对于DistributionGraphVisualizer,add方法实际上并不更新图形。相反,它在第三行调用updateGui。
public synchronized void updateGui(Sample s) { // We have received one more sample if (delay == counter) { updateGui(); counter = 0; } else { counter++; } }
与GraphVisualizer不同,分布图试图显示结果如何聚集;因此DistributionGraphVisualizer会延迟更新。默认延迟为10 个样本结果。
public synchronized void updateGui() { if (graph.getWidth() < 10) { graph.setPreferredSize( new Dimension(getWidth() - 40, getHeight() - 160)); } graphPanel.updateUI(); graph.repaint(); }
如果用户调整窗口大小或拖动分隔线,则假设第 2 到 3 行调整图形大小。第 7 行更新了包含图表的面板。第 8 行触发DistributionGraph的更新。在我们讨论编写图表之前,可视化工具必须实现几个重要的方法。
public String getLabelResource() { return "distribution_graph_title"; }
标签资源从属性文件中检索可视化工具的名称。该文件位于core/org/apache/jmeter/resources中。最好不要硬编码可视化工具的名称。 Message.properties文件按字母顺序组织,因此添加新条目很容易。
public synchronized void clear() { this.graph.clear(); model.clear(); repaint(); }
JMeter 中的每个组件都应该实现clear()方法的逻辑。如果不这样做,当用户尝试清除最后的结果并运行新的测试时,组件将不会清除 UI 或模型。如果未实现 clear,则可能导致内存泄漏。
public JComponent getPrintableComponent() { return this.graphPanel; }
可视化工具应该实现的最后一个方法是getPrintableComponent()。该方法负责返回可以保存或打印的 JComponent。最近添加了此功能,以便用户可以保存任何给定可视化工具的屏幕截图。
29.4 图形监听器¶
Visualizers 应该实现GraphListener。这样做是为了更简单地将新的 Sample 实例添加到侦听器。作为一般规则,如果自定义图形不绘制每个样本,则不需要实现接口。
public interface GraphListener { public void updateGui(Sample s); public void updateGui(); }
接口中的重要方法是updateGui(Sample s)。从 DistributionGraphVisualizer中,我们看到它调用了 graph.repaint() 来刷新图形。在大多数情况下,updateGui(Sample s)的实现应该做到这一点。 ItemListenerVisualizers一般不需要实现这个接口。该界面与组合框、复选框和列表一起使用。如果您的可视化器使用其中之一并且需要知道它何时更新,则可视化器将需要实现该接口。有关如何实现接口的示例,请查看GraphVisualizer。
29.5 编写自定义图¶
对于那些刚接触 Swing 并且还没有编写自定义 JComponents 的人,我建议买一本关于 Swing 的书,并很好地了解 Swing 小部件的工作原理。本教程不会尝试解释基本的 Swing 概念,并假设读者已经熟悉 Swing API 和 MVC(模型视图控制器)设计模式。从DistributionGraphVisualizer的构造函数中,我们看到 DistributionGraph 的新实例是使用模型实例创建的。
public DistributionGraph(SamplingStatCalculator model) { this(); setModel(model); }
setModel方法 的实现很简单。
private void setModel(Object model) { this.model = (SamplingStatCalculator) model; repaint(); }
请注意,该方法在设置模型后 调用repaint 。如果未调用repaint,则可能导致 GUI 无法绘制图形。一旦测试开始,图形就会重绘,因此调用repaint并不重要。
public void paintComponent(Graphics g) { super.paintComponent(g); final SamplingStatCalculator m = this.model; synchronized (m) { drawSample(m, g); } }
更新小部件的另一个重要方面是将对 drawSample的调用放在同步块中。如果drawSample未同步,JMeter 将在运行时抛出 ConcurrentModificationException。根据测试计划,可能有十几个或更多线程将结果添加到模型中。同步块不会影响每个单独请求和时间测量的准确性,但会影响 JMeter 生成大负载的能力。随着测试计划中线程数量的增加,线程必须等到图形完成重绘后再开始新请求的可能性也会增加。这是drawSample的实现。
private void drawSample(SamplingStatCalculator model, Graphics g) { width = getWidth(); double height = (double)getHeight() - 1.0; // first lets draw the grid for (int y=0; y < 4; y++){ int q1 = (int)(height - (height * 0.25 * y)); g.setColor(Color.lightGray); g.drawLine(xborder,q1,width,q1); g.setColor(Color.black); g.drawString(String.valueOf((25 * y) + "%"),0,q1); } g.setColor(Color.black); // draw the X axis g.drawLine(xborder,(int)height,width,(int)height); // draw the Y axis g.drawLine(xborder,0,xborder,(int)height); // the test plan has to have more than 200 samples // for it to generate half way decent distribution // graph. The larger the sample, the better the // results. if (model != null && model.getCount() > 50) { // now draw the bar chart Number ninety = model.getPercentPoint(0.90); Number fifty = model.getPercentPoint(0.50); total = model.getCount(); Collection values = model.getDistribution().values(); Object[] objval = new Object[values.size()]; objval = values.toArray(objval); // we sort the objects Arrays.sort(objval,new NumberComparator()); int len = objval.length; for (int count=0; count < len; count++) { // calculate the height Number[] num = (Number[])objval[count]; double iper = (double)num[1].intValue() / (double)total; double iheight = height * iper; // if the height is less than one, we set it // to one pixel if (iheight < 1) { iheight = 1.0; } int ix = (count * 4) + xborder + 5; int dheight = (int)(height - iheight); g.setColor(Color.blue); g.drawLine(ix -1,(int)height,ix -1,dheight); g.drawLine(ix,(int)height,ix,dheight); g.setColor(Color.black); // draw a red line for 90% point if (num[0].longValue() == ninety.longValue()) { g.setColor(Color.red); g.drawLine(ix,(int)height,ix,55); g.drawLine(ix,(int)35,ix,0); g.drawString("90%",ix - 30,20); g.drawString( String.valueOf(num[0].longValue()), ix + 8, 20); } // draw an orange line for 50% point if (num[0].longValue() == fifty.longValue()) { g.setColor(Color.orange); g.drawLine(ix,(int)height,ix,30); g.drawString("50%",ix - 30,50); g.drawString( String.valueOf(num[0].longValue()), ix + 8, 50); } } } }
一般来说,图形的渲染应该相当快,不应该成为瓶颈。作为一般规则,分析自定义插件是一个好主意。确保可视化器不是瓶颈的唯一方法是使用 Borland OptimizeIt 之类的工具运行它。测试插件的一个好方法是创建一个简单的测试计划并运行它。堆和垃圾收集行为应该是有规律的和可预测的。
29.6 为 JMeter 制作 TestBean 插件¶
在这一部分中,我们将介绍使用新的TestBean框架 为 JMeter 创建一个简单组件的过程。
该组件将是一个 CSV 文件读取元素,可让用户使用 CSV 文件轻松更改其输入数据。要最有效地使用本教程,请打开下面指定的三个文件(位于 JMeter 的src/components目录中)。
- 选择一个包并制作三个文件:
- [组件名称].java (org.apache.jmeter.config.CSVDataSet.java)
- [组件名称]BeanInfo.java (org.apache.jmeter.config.CSVDataSetBeanInfo.java)
- [组件名称]Resources.properties (org.apache.jmeter.config.CSVDataSetResources.properties)
-
CSVDataSet.java必须实现TestBean接口。此外,它将扩展
ConfigTestElement,并实现LoopIterationListener。
- TestBean是一个标记接口,所以没有要实现的方法。
- 扩展ConfigTestElement将使我们的组件成为测试计划中的Config元素。通过扩展不同的抽象类,您可以控制组件的元素类型(即AbstractSampler、AbstractVisualizer、GenericController等 - 尽管您也可以通过实例化正确的接口来制作不同类型的元素,抽象类可以让您的生活更轻松)。
-
CSVDataSetBeanInfo.java应该扩展org.apache.jmeter.testbeans.BeanInfoSupport
- 创建一个零参数构造函数,我们在其中调用super(CSVDataSet.class);
- 我们会回到这个。
- CSVDataSetResources.properties - 暂时为空
- 为您的插件类实现您的特殊逻辑。
- CSVDataSet将读取单个 CSV 文件并将找到的值存储到 JMeter 的运行上下文中。用户将定义文件,为每个“列”定义变量名称。CSVDataSet将在测试开始时打开文件,并在测试结束时关闭它(因此我们实现了TestListener)。CSVDataSet将通过读取文件中的新行来更新每个测试线程以及通过其父控制器的每次迭代的变量内容。当我们到达文件的末尾时,我们将从头开始。实现TestBean 时,请注意您的属性。这些属性将成为用户配置CSVDataSet元素的 GUI 表单的基础。
- 测试开始时,您的元素将被 JMeter 克隆。每个线程都会得到它自己的实例。但是,如果需要,您将有机会控制克隆的完成方式。
- 属性:文件名、变量名。使用公共 getter 和 setter。
- 文件名是不言自明的,它将保存我们将读取的 CSV 文件的名称
- variableNames是一个字符串,它允许用户输入我们将为其赋值的变量的名称。为什么是字符串?为什么不是收藏?用户肯定需要输入多个(未知数量的)变量名吗?没错,但是如果我们使用 List 或 Collection,我们就必须编写一个 GUI 组件来处理集合,而我只想快速完成。相反,我们将让用户输入以逗号分隔的变量名称列表。
- 然后我实现了LoopIterationListener接口的IterationStart方法。这个“事件”的重点是当测试进入它的父控制器时,你的组件会收到通知。出于我们的目的,每次进入CSVDataSet的父控制器时,我们都会读取数据文件的新行并设置变量。因此,对于常规控制器,通过测试的每个循环都将导致读取一组新值。对于循环控制器,每次迭代都会这样做。每个测试线程也会得到不同的值。
- 在CSVDataSetBeanInfo中设置您的 GUI 元素:
- 您可以为组件的属性创建分组。您创建的每个分组都需要一个标签和一个要包含在该分组中的属性名称列表。IE:
createPropertyGroup("csv_data", new String[] { "filename", "variableNames" });
- 创建一个名为csv_data的分组,该分组将包括CSVDataSet的filename和variableNames属性的GUI 输入元素
。然后,我们需要定义我们想要这些属性的类型:
p = property("filename"); p.setValue(NOT_UNDEFINED, Boolean.TRUE); p.setValue(DEFAULT, ""); p.setValue(NOT_EXPRESSION, Boolean.TRUE); p = property("variableNames"); p.setValue(NOT_UNDEFINED, Boolean.TRUE); p.setValue(DEFAULT, ""); p.setValue(NOT_EXPRESSION, Boolean.TRUE);
这实质上创建了两个属性,其值不允许为null,其默认值为""。可以为每个属性设置几个这样的属性。这是一个纲要:- NOT_UNDEFINED
- 该属性不会保留为null。
- 默认
- 如果NOT_UNDEFINED为true ,则必须给出默认值。
- NOT_EXPRESSION
- 如果为true,则不会为函数解析该值。
- NOT_OTHER
- 这不是一个自由形式的输入字段——必须提供一个值列表。
- 标签
- 使用String[]作为值,这将设置一个预定义的可接受值列表,并且 JMeter 将创建一个下拉选择。
p.setPropertyEditorClass(FileEditor.class);
这将创建一个文本输入和浏览按钮,该按钮打开一个查找文件的对话框。通常,不需要像现在这样复杂的属性设置。有关更复杂的示例,请查看org.apache.jmeter.protocol.http.sampler.AccessLogSamplerBeanInfo
- 您可以为组件的属性创建分组。您创建的每个分组都需要一个标签和一个要包含在该分组中的属性名称列表。IE:
- 定义您的资源字符串。在CSVDataSetResources.properties中,我们必须定义所有字符串资源。要提供翻译,可以创建额外的文件,例如
CSVDataSetResources_ja.properties和CSVDataSetResources_de.properties。对于我们的组件,我们必须定义以下资源:
- 显示名称
- 这将为将出现在菜单中的元素提供一个名称。
- csv_data.displayName
- 我们创建了一个名为csv_data的属性分组,因此我们必须为分组提供一个标签
- 文件名.displayName
- 文件名输入元素的标签。
- 文件名.shortDescription
- 类似工具提示的帮助文本简介。
- variableNames.displayName
- 变量名称输入元素的标签。
- variableNames.shortDescription
- variableNames输入元素的工具提示。
- 调试您的组件。
29.6 构建 JMeter ¶
JMeter 使用 Gradle 编译和构建发行版。JMeter 定义了几个任务,这使开发人员更容易构建完整的项目。对于不熟悉 Gradle 的人来说,它是一个类似于 Unix 上的 make 的构建工具。gradle.md中提供了带有简短描述的 Gradle 任务列表,可以在根源目录中找到。
以下是一些示例命令。
- ./gradlew runGui
- 构建并启动 JMeter GUI
- ./gradlew createDist
- 构建项目并将相关的jar文件复制到./lib文件夹
- ./gradlew :src:dist:previewSite
- 创建站点的预览到./build/docs/site