Junit4: 添加参数化运行之前和之后的注释

创建于 2009-11-16  ·  39评论  ·  资料来源: junit-team/junit4

目前,在运行参数化实例之前或之后调用方法没有简单的方法。

换句话说,除了@BeforeClass@AfterClass之外,还应该有@BeforeParameterRun @AfterParameterRun。 每个在参数化实例运行之前/之后触发。

feature parameterized

最有用的评论

伙计们,每次参数化运行的“之后/之前”将非常有用。

所有39条评论

@Before注释本身的参数怎么样:@Before(true) 或@Before(onEachParameter = true)。 当然,默认为 false。

此请求的目标是有一个地方放置在参数运行执行之前和之后运行的代码。 不是在给定参数运行的每个测试之前。 因此,订单将是 BP BT T1p1 AT BT T2p1 AT BT T3p1 AT AP BP BT T1p2 AT BT T2p2 AT ... 其中

  • BP 是前参数运行方法@BeforeParameterRun
  • BT 是前测试方法@Before
  • Txpy 是参数 y @Test上的第 x 个测试,例如 T2P3 是参数 3 上的测试 2
  • AT 是后测方法@After
  • AP 是 after 参数运行 @AfterParameterRun

我在我的 github 上实现了这个,但是由于我的雇主的问题不得不把它删除。 我向 David Saff 发出了拉动,他将其包含在他的分支中,但后来又被取出了。 我将在此消息之后查找包含代码的修订号。

看起来合并是在 2009 年 4 月 3 日左右合并到一棵 dsaff 的树。在评论中,您可以看到来自 bigmikef 的合并。 它已经过时了,但当时确实有效。

伙计们,每次参数化运行的“之后/之前”将非常有用。

这可以使用规则来完成,特别是 ExternalResource。 为每个参数调用实现的方法:

@RunWith(Parameterized.class)
public class ParameterRuleTest {
    @Parameters()
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[]{}, new Object[]{});
    }

    <strong i="6">@Rule</strong>
    public ExternalResource externalResource = new ExternalResource() {
        protected void before() throws Throwable { System.out.println("before"); }
        protected void after() { System.out.println("after"); }
    };

    <strong i="7">@Test</strong> public void myTest1() { System.out.println("test"); }
}

这产生

test
after
before
test
after

如果这是可以接受的,请关闭此问题。

@matthewfarwell我可能误解了您的回答,但在您提供的示例中,该规则将在每次测试之前和之后为参数化运行器创建的每个实例运行。

我认为@bigmikef想要的是能够为参数化运行器创建的每个实例运行一次之前和之后的方法。 我认为@ClassRule不能在这种情况下使用,因为它在静态上下文中运行,并且只对所有参数化实例执行一次。

我不介意主动实施这一点,因为这对我当前的项目是有益的。 我的建议如下:

实施总结:

JUnit 的传统架构是每个测试方法都有一个 Java 类的实例。 为了实现上述要求,我认为需要修改Parameterized运行程序,以便为每个参数化实例创建一个 Java 实例。

主要原因是每次参数化运行之前和之后执行的逻辑对于类来说是本地的,而不是使用静态修饰符放在某个全局范围内。 在我的特定用例中,我已经设置和拆除需要使用每个参数化实例唯一的参数。

添加/修改:

org.junit.runners.Parameterized

  • 添加一个名为ParameterRule的新注释。
  • 添加一个扩展TestClassRunnerForParameters的新受保护内部类,命名为SingleInstanceRunnerForParameters
  • 实例化TestClassRunnerForParametersSingleInstanceRunnerForParameters取决于ParameterRule是否存在。

org.junit.runners.BlockJUnit4ClassRunner

  • 将测试对象的创建移出methodBlock 。 改为提供测试对象作为参数。

    • 这样做的主要原因是扩展类可以将自己的实例传递给methodBlock.否则,如果有人想扩展BlockJUnit4ClassRunner并保留他们必须复制以下方法的大部分功能: withRuleswithMethodRuleswithTestRulesgetMethodRules

  • 如果将测试对象的创建移出methodBlock是不可接受的,那么将以下方法从私有更改为受保护将减少代码重复:

    • withRules

    • withMethodRules

    • withTestRules

    • getMethodRules

org.junit.runners.Parameterized.SingleInstanceRunnerForParameters

  • 添加一个名为withParameterRules的方法,该方法将执行由ParameterRule注释的规则。
  • 在 classBlock 的覆盖版本中执行withParameterRules classBlock

如果有偏好提供此实现的示例,我可以在我的 fork 上提供,但我想在投入大量时间之前讨论设计。

@coreyjv @matthewfarwell的回答有什么问题?

@Tibor17 ,请参阅我对他的回答的回复: https ://github.com/KentBeck/junit/issues/45#issuecomment -11293228

他的实现在每个测试方法之前和之后执行。 就我而言,我的设置和拆除非常昂贵,这就是为什么我想在每次参数化运行之前和之后执行它。

例如,如果我有一个测试类,当使用通用设置(当前位于@ClassRule中)执行一次时,整个类将在大约 20 秒内执行并完成测试。 但是,如果我将设置移动到方法级别规则,则执行和完成大约需要 240 秒。 这只是一节课。 在我的情况下,增加时间是不可接受的。

从理论上讲,我可以将所有测试放在一个方法中以模拟所需的行为,但我认为这不是可维护的测试设计。

@Tibor17 ,我不确定通知是否会在更新时发出,所以我想我会再发表评论。

@dsaff ,对这个提议有什么想法吗?

@coreyjv
基本上你想要的是@BeforeParams@AfterParams在生命周期中只执行一次。 我对吗?

@Tibor17 ,基本上是的。 我想我会使用一个允许规则执行的注释。

如果我使用 BeforeClass (BC) 和 AC,它会是这样吗?
BC BP BT T1p1 AT BT T2p1 AT BT T3p1 AT AP BP BT T1p2 AT BT T2p2 AT AC

@Tibor17 ,是的,我相信您所提供的内容是准确的。

@coreyjv
我认为您想要的这个功能可能很有趣。 你真正的用例是什么?

@Tibor17
我目前正在使用Selenium构建一个 Web 浏览器测试套件来导航和检查页面内容,该页面内容被馈送到 JUnit 以执行测试用例。

我的需求导致每页都有一个 JUnit 测试类来测试以下内容:

  • 是否存在字段?
  • 它是只读的吗?
  • 标签文本是“X”吗?

这些页面可能位于应用程序内的任意深度,因此我将导航逻辑放在“之前”规则(当前为@ClassRule)中以到达目标页面。 理想情况下,我想使用不同的参数运行相同的测试,这些参数在“设置”中读取和使用。 这些参数将是诸如用户标识符和密码凭证之类的项目以及与到达目标页面相关的其他细节。

我将引用我之前写的关于我为什么要按“生命周期”执行此操作的回复:

例如,如果我有一个测试类,当使用通用设置(当前位于@ClassRule中)执行一次时,整个类将在大约 20 秒内执行并完成测试。 但是,如果我将设置移动到方法级别规则,则执行和完成大约需要 240 秒。 这只是一节课。 在我的情况下,增加时间是不可接受的。

@coreyjv
意味着参数也必须在新注释的设置中可见。
这给出了需求的整体概述。
继续。

@Tibor17 ,正确的参数必须在设置中可见。 您希望我提供什么样的额外说明或详细信息?

我认为概述和我之前的评论很好地说明了我的需求(您也可以查看邮件列表),而无需深入了解我认为会增加有限价值的应用程序细节。

@coreyjv
也许您现在应该推动并在此问题中包括人们。

@Tibor17
这对我来说很好,我只是在继续之前寻找“设计”的初步批准。

@coreyjv
我很想看到一些描述使用的测试,即使跑步者的 impl 不完整。
其他人会怎么说测试...

@Tibor17

其他人会怎么说测试...

您在找我发布示例测试课程吗? 这真的很无聊,因为它就像任何其他参数化测试(例如从数据库中读取参数)一样,并且“生命周期”设置将用于代替@ClassRule@Rule设置。 正如我之前提到的,一个简单的案例是设置使用用户名、密码和应用程​​序角色的不同组合。

我不认为这是不寻常的。 只是在这种情况下,在每种方法之前和之后进行设置都非常昂贵。

@coreyjv

在你的测试中这样做怎么样

@BeforeParameter
public void static setup() { // flag this call in some variable and assert it's set }

@Tibor17
正如我之前提到的,这个设置需要参数化,并且对于@Parameters返回的每组参数都是唯一的,所以我认为这种方法行不通。

@coreyjv
我想你已经有了一些快照代码。
你还想在这里讨论还是想开个拉?

@Tibor17
我会把它放在一起并提交一个拉取请求。 我可能要等到新年之后才能完成它,但我会看看我能做些什么。 感谢您的讨论,我很感激。

想法:

  1. 我们应该做到这一点,我很高兴与感兴趣的各方合作。
  2. 我们不能更改任何受保护方法的签名。 但是提取一个受保护的方法块(FrameworkMethod 方法,对象测试)听起来是个好主意。
  3. 在编写 ParameterRule 接口时,请记住,我认为我们需要改进 Rule 和 ClassRule 的工作方式。 https://docs.google.com/document/d/1B6Z45BSGsY08rZqe2KUZTJ3RVsnUE1-HcXjl5MFm9ls/edit有助于解释我希望在哪里看到事情的进展: ParameterRule 可以特别受益于这种规则工厂方法,因为它可以轻松重用诸如临时文件夹之类的东西。
  4. 我认为我们不能单方面改变 Parameterized 的实例化模式,因为当前的测试可能取决于每个测试一个实例的行为。 我们如何解决这个问题?

一种。 添加注释或注释参数以启用不同的行为。
湾。 创建具有不同行为的 Parameterized 子类。
C。 另一个想法是为每个测试创建一个测试类的新实例,但将相同的参数对象数组传递给该实例,该参数对象数组可以通过参数规则进行操作。 如果将参数捆绑到单个对象中,这可能是最有价值的。 一个可能很疯狂的想法是将 ParameterRule 附加到参数类本身......

我认为我更喜欢 c 而不是 b,和 b 而不是 a,但可以讨论。

@dsaff

我们应该做到这一点,我很高兴与感兴趣的各方合作。

谢谢!

我们不能更改任何受保护方法的签名。 但是提取一个受保护的方法块(FrameworkMethod 方法,对象测试)听起来是个好主意。

我今天早上实现了我的要求,最后我没有修改这个方法签名(我采用了将某些内部方法从私有 --> 保护更改的方法)。

在编写 ParameterRule 接口时,请记住,我认为我们需要改进 Rule 和 ClassRule 的工作方式。 https://docs.google.com/document/d/1B6Z45BSGsY08rZqe2KUZTJ3RVsnUE1-HcXjl5MFm9ls/edit有助于解释我希望在哪里看到事情的进展: ParameterRule 可以特别受益于这种规则工厂方法,因为它可以轻松重用诸如临时文件夹之类的东西。

我会看看这个并记住它。

我认为我们不能单方面改变 Parameterized 的实例化模式,因为当前的测试可能取决于每个测试一个实例的行为。 我们如何解决这个问题?

我的实现取决于 @ParameterRule注释的存在。 如果它检测到一个方法或字段被这个注解注解,它将改变 Parameterized 的实例化模式。

一种。 添加注释或注释参数以启用不同的行为。

往上看。

湾。 创建具有不同行为的 Parameterized 子类。

这绝对可以作为一个子类来实现,我也可以。 我的想法是使用现有的类,因为这似乎是发起者的意图。

C。 另一个想法是为每个测试创建一个测试类的新实例,但将相同的参数对象数组传递给该实例,该参数对象数组可以通过参数规则进行操作。 如果将参数捆绑到单个对象中,这可能是最有价值的。 一个可能很疯狂的想法是将 ParameterRule 附加到参数类本身......

我不确定我是否完全遵循,但我是否仍然可以实现对从@Parameters方法返回的每个参数数组执行一次通用设置的要求?

你愿意我提交一个拉取请求,以便我们有实际的代码来讨论吗?

@coreyjv ,是的,我认为如果您有愿意分享的代码,那是很好的下一步。 谢谢!

@dsaff

听起来不错,我会在接下来的几天内尝试一起获取拉取请求。

@dsaff
@coreyjv

有没有解决这个问题? 我们有一些 Junit 测试使用参数选项来指定不同的浏览器,例如 IE/Firefox/Chrome,并且它为每个测试启动一个新浏览器,但是为了提高运行测试的速度,我试图切换到启动并围绕一类测试停止浏览器。 如果我使用 beforeClass 和 afterClass 则在参数之一完成和关闭浏览器之间有太多时间,因此远程 Web 驱动程序超时。 我想使用这种 AfterParameterRun 方法,但我看到了很多讨论,并且这个问题导致了几个拉取请求,但看起来好像没有任何东西被合并到 main 中?
谢谢,
布拉德利

我也有一个案例,我希望看到一个“AfterParameter”函数。

@coreyjv管道中是否存在此功能,因为我们正在运行需要此类注释的参数化测试用例。 @BeforeParam@AfterParam都是必需的。

@bileshg——

根据@dsaff ,这个请求在几年前被“封存”了。 如果他想再次出现,我会顺从他。 此外,我不确定这是否更适合现在的 JUnit 5(我没有跟上那里的进展)。

@coreyjv好的。 感谢您的回复。 实际上,我需要它来做其他事情 - 根据参数获取失败的测试用例计数。 看看这个问题

我看到“@BeforeParam/@ AfterParam for Parameterized runner #1435”被合并并添加到 4.13 发行说明中。 这是否意味着将发布 4.13 版本? 什么时候? 我急需这个功能! 我在 JUnit 5 中没有看到它,所以我想知道何时可以使用 @BeforeParam/@ AfteParam

@dstaraster目前大部分 JUnit 团队都专注于发布 JUnit 5.0。 我希望不久之后我们可以开始 4.13 版本。

@kcooney我对这些@BeforeParam@AfterParam注释也很感兴趣(不幸的是还没有准备好将我的数千个测试迁移到JUnit5)。
4.13 版本是否仍然值得期待?

@raubel我打开 #1496 讨论 4.13 版本。

JUnit5 可以运行 JUnit4 风格的测试,因此您不需要迁移所有测试来使用 JUnit5 功能。

此页面是否有帮助?
0 / 5 - 0 等级