Java 使用 mockito 或 Jmockit 模拟私有静态最终字段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30703149/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:01:52  来源:igfitidea点击:

Mock private static final field using mockito or Jmockit

javajunitmockitostatic-membersjmockit

提问by RaT

I am using private static final LOGGERfield in my class and I want LOGGER.isInfoEnabled()method to return false. How can I mock the static final field by using mockito or jMockit

我在我的班级中使用私有静态最终 LOGGER字段,我希望LOGGER.isInfoEnabled()方法返回false。如何使用 mockito 或 jMockit 模拟静态最终字段

My class is:

我的班级是:

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

  public class Class1 {

  private static final Logger LOGGER = LoggerFactory.getLogger(Class1.class);

    public boolean demoMethod() {
       System.out.println("Demo started");
       if (LOGGER.isInfoEnabled()) {
         System.out.println("@@@@@@@@@@@@@@ ------- info is enabled");
       } else {
         System.out.println("info is disabled");
       }
       return LOGGER.isInfoEnabled();
    }
  }

and its junit is :

它的junit是:

import mockit.Mocked;
import mockit.NonStrictExpectations;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import static org.testng.Assert.*;
import com.source.Class1;

public class MyTest {

  @InjectMocks
  Class1 cls1;

  @BeforeMethod
  public void initMocks() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void test(@Mocked final Logger LOGGER) {

    new NonStrictExpectations() {
      {
        LOGGER.isInfoEnabled();
        result = false;
      }
    };
    assertFalse(cls1.demoMethod());
  }
}

when I run it the result is:

当我运行它时,结果是:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.test.MyTest
Configuring TestNG with: TestNG652Configurator
Demo started
@@@@@@@@@@@@@@ ------- info is enabled
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.9 sec <<< FAILURE! - in com.test.MyTest
test(com.test.MyTest)  Time elapsed: 0.168 sec  <<< FAILURE!
java.lang.AssertionError: expected [false] but found [true]
        at com.test.MyTest.test(MyTest.java:35)


Results :

Failed tests:
  MyTest.test:35 expected [false] but found [true]

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9.899s
[INFO] Finished at: Mon Jun 08 12:35:36 IST 2015
[INFO] Final Memory: 16M/166M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project JMockDemo: The
re are test failures.
[ERROR]
[ERROR] Please refer to D:\perfoce_code\workspace_kepler\JMockDemo\target\surefire-reports for the individual test results.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

I am new to jmockit and I want my above junit case to run successfully. And I have to use JMockit or mockito, can't use Powermockito. Please help.

我是 jmockit 的新手,我希望我上面的 junit 案例能够成功运行。而且我必须使用JMockit或mockito,不能使用Powermockito。请帮忙。

采纳答案by Nitin Dandriyal

One way is using reflection get rid of finalmodifier from the field and then replace the LOGGERfield with Mocked one

一种方法是使用反射final从字段中删除修饰符,然后LOGGER用 Mocked one替换该字段

public class Class1Test {
    @Test
    public void test() throws Exception {
        Logger logger = Mockito.mock(Logger.class);
        Mockito.when(logger.isInfoEnabled()).thenReturn(false);
        setFinalStatic(Class1.class.getDeclaredField("LOGGER"), logger);
        Class1 cls1 = new Class1();
        assertFalse(cls1.demoMethod());
    }

    static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);        
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }
}

回答by Kalyan Chavali

I think mockito or jMockit cant mock static final classes as they try to override the methods while unit testing. However, powerMockito can as it uses Reflection and mocks the static final class/methods.

我认为 mockito 或 jMockit 不能模拟静态最终类,因为它们在单元测试时试图覆盖这些方法。但是,powerMockito 可以使用反射并模拟静态最终类/方法。

回答by RaT

Changing "@Mocked Logger" to "@Capturing Logger" in the parameter makes it work. like

将参数中的“@Mocked Logger”更改为“@Capturing Logger”使其工作。喜欢

  @Test
  public void test(@Capturing final Logger LOGGER) {

    new NonStrictExpectations() {
      {
        LOGGER.isInfoEnabled();
        result = false;
      }
    };
    assertFalse(cls1.demoMethod());
  }