Java “最干净的方式”;“咖喱”;可运行

Java “最干净的方式”;“咖喱”;可运行,java,junit,runnable,currying,Java,Junit,Runnable,Currying,我正在编写一个JUnit测试,希望在一个对象有几个不同变量的地方运行测试。我通过传递runnables来避免深度嵌套的循环 private Runnable withAges( final Person person, final Runnable r ) { return () -> { person.setAge( 0 ); r.run(); person.setAge( 50 ); r.run();

我正在编写一个JUnit测试,希望在一个对象有几个不同变量的地方运行测试。我通过传递runnables来避免深度嵌套的循环

private Runnable withAges( final Person person, final Runnable r ) {
    return () -> {
        person.setAge( 0 );
        r.run();
        person.setAge( 50 );
        r.run();
        person.setAge( Integer.MAX_VALUE );
        r.run();
        person.setAge( -1 );
        r.run();
        person.setAge( Integer.MIN_VALUE );
        r.run();
    };
}

private Runnable withHair( final Person person, final Runnable r ) {
    return () -> {
        person.setHair( "blonde" );
        r.run();
        person.setHair( "BLONDE" );
        r.run();
        person.setHair( null );
        r.run();
    };
}

private Runnable withAddresses( final Person person, final Runnable r ) {
    ...
}

private Runnable withChildren( final Person person, final Runnable r ) {
    ...
}
实际测试为:

@Test
void testPerson() {
    final Person person = new Person();
    final Runnable tests = () -> {
        assertTrue( ... );
        assertFalse( ... );
    }
    ...
}
目前,我可以使用

withAges( person,
          withHair( person,
                    withAddresses( person,
                                   withChildren( person, tests ) ) ) );
然而,如果我能写下这样的东西来清理它,那就太好了

withAges( person ).withHair( person ).withAddresses( person ).withChildren( person ).tests.run();

通过使
site
成为一个实例变量,我能够将它从
withX()
签名中删除。这让我可以通过

withAges( withHair( withAddresses( withChildren( tests ) ) ) ).run()

通过使
site
成为一个实例变量,我能够将它从
withX()
签名中删除。这让我可以通过

withAges( withHair( withAddresses( withChildren( tests ) ) ) ).run()

不要误解这一点:你目前的方法和你想要的方法都很难遵循

据我所知,您正在尝试测试
人员
的一系列参数组合

这是一种明显的非惯用方式。除此之外,您还必须非常小心地恢复
人员的可变状态,以避免在测试之间发生干扰

您可能会发现类似JUnit理论的方法更容易做到这一点:

@DataPoints("ages") Set<Integer> ages = Set.of(0, 50, Integer.MIN_VALUE, -1 /* etc */);
@DataPoints("hairs") Set<String> hairs = Set.of("blonde", "BLONDE" /* etc */);
/* etc */

@Theory
public void testSomething(
    @FromDataPoints("ages") Integer age, @FromDataPoints("hairs") String hair) {
  Person person = new Person();
  person.setAge(age);
  person.setHair(hair);

  assertTrue(...);
  assertFalse(...);
}

不要误解这一点:你目前的方法和你想要的方法都很难遵循

据我所知,您正在尝试测试
人员
的一系列参数组合

这是一种明显的非惯用方式。除此之外,您还必须非常小心地恢复
人员的可变状态,以避免在测试之间发生干扰

您可能会发现类似JUnit理论的方法更容易做到这一点:

@DataPoints("ages") Set<Integer> ages = Set.of(0, 50, Integer.MIN_VALUE, -1 /* etc */);
@DataPoints("hairs") Set<String> hairs = Set.of("blonde", "BLONDE" /* etc */);
/* etc */

@Theory
public void testSomething(
    @FromDataPoints("ages") Integer age, @FromDataPoints("hairs") String hair) {
  Person person = new Person();
  person.setAge(age);
  person.setHair(hair);

  assertTrue(...);
  assertFalse(...);
}

使用参数化测试这样的东西不是更容易吗?对我来说似乎也有点过度设计了/您有嵌套的循环。关于嵌套循环的论点是,内部部分被称为
m*n*o*p
times。数一数你调用它的次数:)不想使用循环,我的意思是我不想让我的测试方法有一个6深的嵌套循环。@MichaelBianconi一个6深的循环比你在这里介绍的间接循环要清楚得多。使用参数化测试这样的东西不是更容易吗?对我来说似乎也有点过度设计了:/您有嵌套的循环。关于嵌套循环的论点是,内部部分被称为
m*n*o*p
times。数一数你调用它的次数:)不想使用循环,我的意思是我不想让我的测试方法有一个6深的嵌套循环。@MichaelBianconi一个6深的循环比你在这里介绍的间接循环清楚得多。