使用构造函数的参数测试抽象类

tjb*_*brn 10 java mockito

我正在尝试学习测试,但在测试抽象类时我遇到了一些问题.我知道我可以创建一个继承自Dog的具体子类,比如ConcreteDog,但是如果我向Dog添加一个新的抽象方法,我将不得不向ConcreteDog添加一个空方法.我想这不会那么酷.

public abstract class Dog {
  private final int id;

  public Dog(int id) {
    this.id = id;
  }

  public int getId() {
    return id;
  }

  public abstract void makeSound();
}

...

public class DogTest {
  @Test
  public void testGetId() {
    int id = 42;

    // How to pass id to Dog constructor ?
    Dog dog = Mockito.mock(Dog.class, Mockito.CALL_REAL_METHODS);

    assertTrue(dog.getId() == id);
  }
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是以某种方式用构造函数调用Mock,就像

Mockito.mock(Dog(id).class, Mockito.CALL_REAL_METHODS);
Run Code Online (Sandbox Code Playgroud)

我不知道是否可以使用mockito,但有一种方法可以使用mockito或其他工具吗?

Aun*_*mag 8

您可以这样做:

Mockito.mock(Dog.class, Mockito.withSettings()
        .useConstructor(999)
        .defaultAnswer(Mockito.CALLS_REAL_METHODS)
);
Run Code Online (Sandbox Code Playgroud)

其中999-是id参数的任何整数。因此,您不必再继承抽象类。您还可以根据需要传递尽可能多的参数,例如:

.useConstructor(new Object(), "my string", 5.5, null)
Run Code Online (Sandbox Code Playgroud)

  • 这是现代方式进行的方式,但我只是想提到您需要Mockito 2.x才能实现此目的。Mockito的1.9.5版本没有提供用于`MockSettings`的`useConstructor()`方法。 (4认同)

Use*_*F40 5

如果需要,您可以使用反射设置字段,这基本上复制了构造函数设置成员字段的方式。

Dog dog = Mockito.mock(Dog.class, Mockito.CALL_REAL_METHODS);
ReflectionTestUtils.setField(dog , "id", 42);
Run Code Online (Sandbox Code Playgroud)


小智 4

由于 Dog 是一个抽象类,我建议首先创建一个子类。

class TestDog extends Dog {
...
}
Run Code Online (Sandbox Code Playgroud)

然后您需要创建 TestDog 的模拟并定义其行为。然后,当您创建 TestDog.class 的实例时,返回 TestDog 的模拟,例如......

TestDog mock_dog = mock(TestDog.class); 
when(mock_dog.getId()).thenReturn(99);
whenNew(TestDog.class).withArguments(anyInt()).thenReturn(mock_dog);
Run Code Online (Sandbox Code Playgroud)

尝试一下并告诉我