在不初始化 class 的情况下测试方法

Test a method without initialize the class

我是单元测试的新手,我想知道是否有一种方法可以在不初始化 class 的情况下测试方法。我问的原因是因为在构造函数中传递了很多对象,这意味着很多模拟存根,而从彻底检查来看 methodToTest 似乎没有使用任何对象属性。这不是我的代码,否则该方法可以转换为静态方法。

class ExampleClass {
   public ExampleClass(FirstClass fc, SecondClass sc, ThirdClass tc) {}

   public void methodToTest(FourthClass foc) {}
}

据我所知,如果不初始化 class,您将无法进行测试。

Test的三个步骤是Arrange、Act和Assert。 class 必须在安排部分初始化,以便在您正在测试的特定 class 中获取所需的方法。

您在这里有一些选择:

  • 将方法设为静态,这样您就不需要引用实际对象。这仅在该方法不需要 ExampleClass 的任何状态时才有效(即它需要的一切都在方法参数中传递)。
  • 将此方法提取到另一个更易于自行测试的 class(可能使用方法对象模式)。此重构称为 replace method with method object.

我不知道你的方法是做什么的,但如果你的应用程序可行,你可以将 methodToTest 设为静态,这样你就可以在没有 class 的实例的情况下调用它。

或者,您可以通过在用于所有测试的 @BeforeClass 方法中创建一个实例来避免过多的实例化,但同样我不知道您的方法做了什么,所以这可能不是理想的。

好的,看来我找到方法了。由于方法与对象的状态无关,我可以模拟对象并命令 MockRunner 在调用时使用真实的方法。它被命名为部分模拟。做法是

    ExampleClass = PowerMockito.mock(ExampleClass.class);
    when(ExampleClass.methodToTest(foc)).thenCallRealMethod();

通常情况下,构造函数中的参数过多是一种错误观念的暗示。您最好重新考虑对象和 classes 以减少提供给构造函数的参数。

如果您不想,您仍然可以使用某种 "TestUtil" 来为您实例化 class。


示例:

public class MyTestUtils {
    public createValidFirstClass() {
        return new FirstClass(/* some arguments here */);
    }
    public createValidSecondClass() {
        return new SecondClass(/* Some arguments here */);
    }
    public createValidThridClass() {
        return new ThridClass(/* Some arguments here */);
    }
    public createValidExampleClass() {
        return new ExampleClass(createValidFirstClass(), createValidSecondClass(), createValidThridClass());
    }
}

这个 class 必须在您的测试包中而不是在您的项目中,并且不应在测试之外使用,这将是一个非常糟糕的做法,在您的实际项目中使用 Factory 或 Builder .



无论如何,我认为最好的解决办法是重新考虑你类。
示例:

public class People {
    public People(String firstName, String lastName, Date birth, Date death) {
    }
}

如您所见,控制所有给定参数的格式是否正确且不为空是一件很痛苦的事情。

通过这种方式可以减少传递给方法的参数数量。

public class People {
    public People(PeopleNames names, Period period) {
    }
}
public class PeopleNames {
    public People(String firstName, String lastName) {
    }
}
public class PeopleNames {
    public People(Date begin, Date end) {
    }
}

使用 PowerMockito 的抑制。

import org.powermock.api.support.membermodification.MemberModifier; import org.powermock.api.support.membermodification.MemberMatcher; suppress(MemberMatcher.constructor(ExampleClass.class))