Java 使用mockito或Jmockit模拟私有静态最终字段
我正在类中使用私有静态最终记录器字段,我希望LOGGER.isInfoEnabled()方法返回false。 如何使用mockito或jMockit模拟静态final字段 我的班级是:Java 使用mockito或Jmockit模拟私有静态最终字段,java,junit,mockito,static-members,jmockit,Java,Junit,Mockito,Static Members,Jmockit,我正在类中使用私有静态最终记录器字段,我希望LOGGER.isInfoEnabled()方法返回false。 如何使用mockito或jMockit模拟静态final字段 我的班级是: import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Class1 { private static final Logger LOGGER = LoggerFactory.getLogger(Class1.
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();
}
}
它的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());
}
}
当我运行它时,结果是:
-------------------------------------------------------
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
-------------------------------------------------------
T T S T S
-------------------------------------------------------
运行com.test.MyTest
使用:TestNG652配置器配置TestNG
演示开始了
@@@@@@@@@@@@@@----信息已启用
测试运行:1,失败:1,错误:0,跳过:0,运行时间:1.9秒我认为mockito或jMockit无法模拟静态最终类,因为它们在单元测试时试图重写方法。但是,powerMockito可以使用反射并模拟静态final类/方法。一种方法是使用反射,从字段中去掉final
修饰符,然后用模拟字段替换LOGGER
字段
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);
}
}
将参数中的“@Mocked Logger”更改为“@Capturing Logger”可使其正常工作。像
@Test
public void test(@Capturing final Logger LOGGER) {
new NonStrictExpectations() {
{
LOGGER.isInfoEnabled();
result = false;
}
};
assertFalse(cls1.demoMethod());
}
接受的解决方案不应与JDK 12一起使用。原因是显而易见的
使用PowerMockito(使用版本2.0.9测试)很容易做到这一点。您可以使用Whitebox.setInternalState方法为您执行此操作
例如:
Whitebox.setInternalState(MyTestClass.class,“myCar”,carMock)代码>
MyTestClass是包含字段的类
myCar是字段的变量名
carMock是一些您希望通过的模拟。您可以为这些元素创建一个setter方法,并在测试时设置一个模拟记录器。是的,它是这样工作的,但我必须使记录器不是最终的,并添加一个setter方法。在不更改实际类的情况下,是否有任何方法可以执行此操作。只需将@Mocked Logger
更改为@Capturing Logger
,它应该会工作。感谢@Rogério也在工作,现在我得到了另一个工作解决方案:-)查看如何使用纯MockitoWow进行此操作太好了,这是我正在寻找的解决方案,非常感谢:-)为什么要将setFinalStatic方法设置为静态,有什么具体原因吗?这非常危险,因为它会改变整个类加载器的静态实例。任何后续的测试/类都将具有记录器的模拟实例。在并行运行测试时也不应使用此选项。这可能会导致测试中出现严重的多线程问题,对此要小心。愚蠢的模拟框架,如果我想模拟它,那么它应该会自动为我更改修改器。@IlkerCat我很快搜索了,但在我的一个项目中没有找到一个示例(这已经很长时间了)。如果我没记错的话,应该可以::DYou不能重写final方法。。只有使用反射才能做到这一点。这对我来说很有效,而且很简单。我不必从记录器中删除最终修改器