【问题标题】:Test a method without initialize the class在不初始化类的情况下测试方法
【发布时间】:2015-07-23 12:50:17
【问题描述】:

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

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

   public void methodToTest(FourthClass foc) {}
}

【问题讨论】:

  • 我认为,你不应该在你的单元测试中假设一个方法在内部做什么。毕竟,单元测试应该检查一个方法是否完成了它的工作,不管它是怎么做的。
  • 您没有创建非参数化构造函数的选项吗?喜欢public ExampleClass() {} 或制作方法static
  • 如果您的问题归结为您想在不调用构造函数的情况下创建对象(无论这意味着什么),请查看stackoverflow.com/questions/3488097/…
  • 为什么不能通过调用构造函数来创建对象并在参数中传递空值并调用methodToTest并传递对象FourthClass?
  • @Ankushsoni 我猜是因为我想避免NullPointerException

标签: java unit-testing mockito powermockito


【解决方案1】:

你有一些选择:

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

【讨论】:

  • 您的第一个解决方案,尽管是一个解决方案,但很糟糕。它基本上建议为了测试目的而改变类的行为,这违背了良好的实践。您的第二个解决方案将是一种更好的方法,但只有当该方法可以轻松地与类分离时才有意义。
  • 我喜欢在这些场景中应用一个经验法则:如果某些东西很难测试,那么被测代码的设计可能有问题。在这个特定示例中,将某些东西设为静态有助于解决问题。它不会“仅用于测试”,因为这揭示了有关该方法的一些额外信息:它不依赖于 ExampleClass 的任何实例变量。我看到这种方法的唯一缺点是存根/模拟这种静态方法变得更加困难。分离职责可能会带来更简洁的设计,但需要更多的额外工作。
【解决方案2】:

通常,在构造函数中有很多参数是对错误概念的暗示。你最好重新考虑你的对象和类,以减少给构造函数的参数。

如果您不想这样做,您仍然可以使用某种“TestUtil”来为您实例化类。


示例:

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());
    }
}

这个类必须在你的测试包中而不是你的项目中,并且不应该在测试之外使用,这将是一个非常糟糕的做法,在你的实际项目中使用 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) {
    }
}

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      据我所知,如果不初始化类,就无法进行测试。

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

          使用 PowerMockito 的抑制功能。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-02-18
            • 1970-01-01
            • 1970-01-01
            • 2012-09-07
            • 1970-01-01
            • 2018-12-19
            • 2019-04-09
            相关资源
            最近更新 更多