简体   繁体   English

模拟抽象类的非抽象方法

[英]Mocking a non-abstract method of an abstract class

I am trying to unit-test a class that extends an abstract base class . 我正在尝试对扩展抽象基class的类进行单元测试。 Here are the "similar classes" for illustration purposes: 以下是用于说明目的的“相似类”:

public abstract class MyAbstractBaseClass {
  @Autowired
  private WaterFilter waterFilter;

  protected List<String> filterComponents(List<String> allComponents) {
    return waterFilter.filter(allComponents);
  }
}

public class MyDerivedClass extends MyAbstractBaseClass {
  public List<String> filterWater(List<String> allWaterComponents) {
    List<String> filteredComponents = this.filterComponents(allWaterComponents); //calls abstract class's filterComponets()
    filteredComponents.add("something-else");
    return filteredComponents;
  }
}

Here is the unit test I am trying: 这是我正在尝试的单元测试:

    @RunWith(EasyMockRunner.class)
    public class MyDerivedClassTest {
        @TestSubject
        private MyDerivedClassTest SUT;

        @Before
        public void setup() {
           SUT = new MyDerivedClassTest();
        }

        @Test
        public void test filterWater_HappyCase() {
           //I want to mock my abstract class's filterComponents() method
           //I am trying this:
           EasyMock.expect(SUT.filterComponents(getDummyComponents())).andReturn(getSomeComponents());

          //What to replay here?
          //EasyMock.replay(...)

          List<String> actualResult = SUT.filterWater(getDummyComponents());

          //assert something
          //What to verify?
          //EasyMock.verify(...)
    }
}

When I run this test, I get 当我运行此测试时,我得到

java.lang.NullPointerException 显示java.lang.NullPointerException

in MyAbstractBaseClass.filter(allComponents) MyAbstractBaseClass.filter(allComponents)

I understand that the autowired "waterFilter" is not getting initialized. 我了解自动接线的“ waterFilter”尚未初始化。 But then, I just want to mock the "non-abstract" method of the abstract class in my unit test. 但是,然后,我只想在单元测试中模拟抽象class的“非抽象”方法。

How should I go about this using EasyMock? 我应该如何使用EasyMock做到这一点? Also, I don't know what to replay() and verify() . 另外,我不知道该怎么replay()verify()

When you write an unit test, you test a object (generally, a method of it) and you may mock a object (generally, a method of it). 编写单元测试时,您将测试一个对象(通常是其方法),并且可以模拟一个对象(通常是其方法)。
However, you should not unit test and mock the same object because in a some way, it seems not very natural : if you test a method of a class, the behavior of the tested class should stay as natural as possible and not fake its own methods. 但是,您不应该对同一对象进行单元测试和模拟,因为从某种程度上来说,这似乎不是很自然:如果您测试类的方法,则被测试类的行为应保持尽可能自然,并且不要伪造自己的行为。方法。
Otherwise, we can wonder if the quality of the unit test is good. 否则,我们会怀疑单元测试的质量是否良好。
Why ? 为什么呢 Because it doesn't reflect the real behavior of the class that we would have at the runtime, but just some part of its behavior. 因为它不能反映类在运行时的真实行为,而只是反映其行为的一部分。 In a unit test, isolation is researched but behind it, the idea is to isolate your under test class only from the other classes and not an isolation of its own behavior. 在单元测试中,研究隔离性,但在其背后,其思想是仅将您的被测类与其他类隔离,而不是隔离其自身的行为。
Of course, you can try to mock a no-abstract method in the abstract class of your under tested class but the design and the quality of your test may become less good. 当然,您可以尝试在被测类的抽象类中模拟一个无抽象方法,但是测试的设计和质量可能会变差。

In your case, I imagine two reasons to mock the no-abstract method in the abstract class : 在您的情况下,我想出了在抽象类中模拟无抽象方法的两个原因:

  • the waterFilter field dependency annoys you because it is not valued, so an exception (NullPointerException) is raised during the test. waterFilter字段依赖项使您烦恼,因为它没有被赋值,因此在测试过程中会引发异常(NullPointerException)。
  • You really want to mock the no abstract method in the abstract class because you have already unitary tested this method and you don't want to duplicate this test. 您真的想在抽象类中模拟no抽象方法,因为您已经对该方法进行了统一测试,并且不想重复该测试。

1) If your the problem is the waterFilter field dependency. 1)如果您的问题是waterFilter字段依赖性。

you should mock the waterFilter field. 您应该模拟waterFilter字段。 To mock a field, it must be accessible and modifiable. 要模拟字段,该字段必须可访问且可修改。 In your case, it's not straight because the field is private. 您的情况并非如此,因为该字段是私有的。

So, you have two ways to access to it to be able to mock it : 因此,您可以通过两种方式对其进行模拟:

  • change your design to give the possibility to set the field from a public method or in the constructor of MyDerivedClass . 更改设计,以便可以从公共方法或MyDerivedClass的构造函数中设置字段。
  • use reflection to set the field (use an API or do it yourself because it's not hard). 使用反射来设置字段(使用API​​或自行完成,因为这并不难)。

You don't need to do verify operations with EasyMock. 您无需使用EasyMock进行验证操作。 Just mock the result returned by waterFilter.filter(allComponents) such as : 只需模拟waterFilter.filter(allComponents)返回的结果,例如:

 waterFilterMock.filter(mockedComponents) 

In this way, the mock returns the value you have chosen and in your JUnit assertion, you are able to do the correct assertion for your method under test. 这样,模拟就返回您选择的值,并且在JUnit断言中,您可以为被测方法做正确的断言。

Just for information, you could use Mockito instead of EasyMock. 仅作为参考,您可以使用Mockito代替EasyMock。 It's more flexible and it offers more readable operations. 它更加灵活,并且提供了更具可读性的操作。 For example, you could do it with Mockito : 例如,您可以使用Mockito做到这一点:

Mockito.when(waterFilterMock.filter()).thenReturn(mockedComponents);

As you can see, it is more readable. 如您所见,它更具可读性。

2) If you problem is that you really want to mock the no-abstract method in the abstract class because you have already unitary tested it 2)如果您的问题是您真的想在抽象类中模拟no-abstract方法,因为您已经对其进行了整体测试

You should modify your design and use composition instead of inheritance. 您应该修改设计并使用组成而不是继承。 You would have not MyAbstractBaseClass any longer but simply a dependency between two classes (the one has a field of the other). 您将不再拥有MyAbstractBaseClass而只需拥有两个类之间的依赖关系(一个类具有另一个字段)。 In this way, you could mock the filterComponents() method in a natural way. 这样,您可以自然地模拟filterComponents()方法。

Expectations has to be set on mocked resources. 必须对模拟资源设定期望。 In your case i think you should inject a mocked instance of WaterFilter. 在您的情况下,我认为您应该注入WaterFilter的模拟实例。

And your expectation,replay and verify should be set on waterFilter object instance. 并且您的期望,重播和验证应在waterFilter对象实例上进行设置。

You can refer to the example provided in given below link. 您可以参考以下链接中提供的示例。 http://www.tutorialspoint.com/easymock/easymock_junit_integration.htm http://www.tutorialspoint.com/easymock/easymock_junit_integration.htm

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM