1

我试图理解简化设计的概念。下面是具有两个具有相同功能的类的代码。

interface Factorial {
   long factorial(long n); 
}

class FactorialA implements Factorial {
   long factorial(long n) {
     // imperative implementation goes here
   }
}
class FactorialB implements Factorial {
   long factorial(long n) {
     // recursive implementation goes here
   }
}
class FactorialB implements Factorial {
   long factorial(long n) {
     // functional implementation goes here
   }
}

...
class FactorialTest {
   @Test
   public void testFactorialA() {
      testFactorial(new FactorialA());
   }
...
   private void testFactorial(Factorial f) {
     assertThat(...)
   }
}

在这种情况下,我将如何减少重复?我曾尝试将它们放在一个类中并使方法静态化,但我被困在如何称呼它上。我也尝试过按照上面的接口,但在这种情况下,单元测试将受到重复测试的困扰。任何有用的提示将不胜感激,因为这将帮助我减少代码中的冗余。如何将上面的代码压缩为一类,减少测试冗余?

4

2 回答 2

1

根据您在评论中的澄清,我会这样做:

interface Factorial {
   long factorial(long n); 
}

class FactorialA implements Factorial {
   long factorial(long n) {
     // imperative implementation goes here
   }
}
class FactorialB implements Factorial {
   long factorial(long n) {
     // recursive implementation goes here
   }
}
class FactorialB implements Factorial {
   long factorial(long n) {
     // functional implementation goes here
   }
}

...
class FactorialTest {
   @Test
   public void testFactorialA() {
      testFactorial(new FactorialA());
   }
...
   private void testFactorial(Factorial f) {
     assertThat(...)
   }
}

所以测试代码不会重复,但是对于每个实现你仍然有一个通过/失败的单元测试。

如果您希望将每个实现都作为静态方法,那么您可以这样做:

class Factorial {
  static long imperative(long n) { ... }
  static long recursive(long n) { ... }
  static long functional(long n) { ... }
}

class FactorialTest {
   @Test
   public void testFactorials() {
      testFactorial(n -> Factorial.imperative(n));
      testFactorial(n -> Factorial.recursive(n));
      testFactorial(n -> Factorial.functional(n));
   }
...
   private void testFactorial(Function<Long,Long> f) {
     assertThat(...)
   }
}
于 2020-10-30T00:13:38.457 回答
1

似乎您的主要问题是如何避免为您的每个接口实现复制测试。

假设您使用的是 JUnit,那么我建议您使用带有方法源的参数化测试。这允许您拥有一个生成每个实现的实例的方法。

解决方案看起来像:

@ParameterizedTest
@MethodSource("factorialProvider")
void testConstants(Factorial impl) {
    assertEquals(1, impl.factorial(1));
}

@ParameterizedTest
@MethodSource("factorialProvider")
void testInduction(Factorial impl) {
    for (int i = 10; i < 20; i++)
        assertEquals(impl.factorial(i) * (i + 1), impl.factorial(i + 1));
}

static Stream<String> factorialProvider() {
    return Stream.of(new FactorialA(), new FactorialB(), new FactorialC());
}

您可以使用同一个提供程序进行任意数量的测试。

于 2020-10-30T00:51:30.327 回答