如何在抽象类中模拟受保护的变量

时间:2019-09-02 13:13:23

标签: java unit-testing mockito abstract-class

Edit2:我只是盲目,没有看到记录器的初始化方式

this.logger = authotrization.getLogger();

在构造函数中,和其他所有构造函数一样,我认为过度劳累,将授权作为参数传递,因此现在很容易,本文无关紧要,谢谢大家的宝贵时间

编辑:所以我编辑了我的问题,以便清楚地知道我要做什么,希望现在是在stackoverflow标准中,我很着急,很抱歉。

以下测试结果为NullPointerException。是否有可能避免这种情况,例如通过嘲笑受保护的logger

abstract public class SomeClass {

    protected Legs legs;
    protected Logger logger;

    public SomeClass(String name, Cat cat) {
        this.legs = cat.getLegs();
        logger.info("Creating new {}", name);
    }

}

在类内部有更多的变量,在构造函数内有更多的参数,这些变量正在为变量分配一些值,但它们不会以任何方式影响记录器,因此我没有提及它们。

这是我的测试班简化了:

@RunWith(PowerMockRunner.class)
public class SomeClassTest {

    private ClassThatExtendsSomeClass classThatExtends;
    @Mock
    private Cat cat;
    @Mock
    private Logger logger;

    @Before
    public void setUp() {
       mock(Cat.class)
       doReturn(new Legs()).when(cat).getLegs();
       mock(Logger.class)
       doNothing().when(logger).info(anyString(), anyObject());
   }

   @Test
   public void test() {
      classThatExtends = new ClassThatExtendsSomeClass("Hello World", cat);
      //it always fails here on the logger line in SomeClass
   }
}

模拟猫是有效的,因为它是作为参数传递的,并且程序知道我要模拟哪只猫,但是对于记录器来说,这并不是因为我无法将其作为参数传递,而且不是@Inject,我也不知道不知道如何让模拟知道我想要这个记录器什么都不做

我会将“ SomeClass”重命名为“ SomeAbstractClass”或类似名称,因此更清晰,但已经有了一个答案,并且会再次破坏它,以解决这个不好的问题,我宁愿在实时聊天中讨论它,但我无法访问它。

1 个答案:

答案 0 :(得分:1)

如果要在构造函数中使用模拟的logger,则需要两个步骤:

  1. 在测试代码中创建模拟。
  2. 将其传递到您的生产代码,例如作为构造函数参数。

样本测试可能如下所示:

import org.junit.Test;
import org.slf4j.Logger;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;

public class SomeClassTest {

    @Test
    public void shouldNotRequireLogger() {
        Logger logger = mock(Logger.class);
        String name = "name";

        SomeClass someClass = new SomeTestClass(logger, name);

        assertNotNull(someClass.logger);
    }

    public class SomeTestClass extends SomeClass {

        SomeTestClass(Logger logger, String name) {
            super(logger, name);
        }

    }

}

避免使用NullPointerException的另一种可能性是预先初始化记录器。但是,它会以这种方式在测试过程中打印日志(可能会有帮助):


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class SomeClass {

    protected static final Logger LOGGER = LoggerFactory.getLogger(SomeClass.class);

    public SomeClass(String name) {
        LOGGER.info("Creating new {}", name);
    }

}

最后,尽管这显然是基于意见的,并且取决于用例,但有人可能会争辩:构造函数不是记录器,因此它只能 construct 对象,而不显示 log 消息。因此,您可以考虑不将logger调用放在构造函数内部,而应该放在其他地方。