使用 PowerMock 在多个测试中模拟 System.class 未按预期工作
Using PowerMock to mock System.class in multiple tests not working as expected
Class 测试中:
public class SystemCaller {
public String callSystem() {
return System.getenv("test-this");
}
}
测试 1:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemCaller.class, System.class})
public class SystemTestOne {
@Before
public void start() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("test-this")).thenReturn("hello-one");
}
@After
public void stop() {}
@Test
public void verifySystemTestOne() throws Exception {
assertThat(new SystemCaller().callSystem(), is("hello-one"));
}
}
测试 2:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemCaller.class, System.class})
public class SystemTestTwo {
@Before
public void start() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("test-this")).thenReturn("hello-two");
}
@After
public void stop() {}
@Test
public void verifySystemTestTwo() throws Exception {
assertThat(new SystemCaller().callSystem(), is("hello-two"));
}
}
如果单独 运行,则每个测试都会自行通过。但是,当我 运行 all 测试时,测试失败。错误各不相同。有时,断言期望 hello-two
,但得到 hello-one
。在其他时候,callSystem()
只是 returns null
!
这里有设置问题吗?或者,这是因为我正在模拟导致问题的 static
方法(在本例中为 System
class)吗?
我的依赖项:
"org.apache.commons" % "commons-lang3" % "3.5" ::
"com.squareup.okhttp3" % "okhttp" % "3.6.0" ::
"com.google.code.gson" % "gson" % "2.8.0" ::
"com.novocode" % "junit-interface" % "0.8" % "test->default" ::
"junit" % "junit" % "4.12" % "test" ::
"org.hamcrest" % "hamcrest-core" % "1.3" % "test" ::
"org.hamcrest" % "hamcrest-library" % "1.3.RC2" % "test" ::
"com.squareup.okhttp3" % "mockwebserver" % "3.8.0" % "test" ::
"org.powermock" % "powermock-core" % "1.6.6" % "test" ::
"org.powermock" % "powermock-api-mockito" % "1.6.6" % "test" ::
"org.powermock" % "powermock-module-junit4" % "1.6.6" % "test" ::
更新 1:
好的,@kevin-welker 的建议使用 EnvironmentVariables
确实奏效了。但是,我看到一个奇怪的问题,当我 运行 来自 Intellij IDEA 的 JUnit 测试(使用 JUnit 运行 配置 )时,一切正常,但是当我 运行 他们通过 sbt
(通过 ./sbt test
)他们失败了同样的错误 :(.
我正在利用 https://github.com/sbt/junit-interface 来 运行 这些测试,但似乎无法让它们发挥作用。
更新 2:
好的!感谢 @kevin-welker 和 @stefan-birkner,我让测试按预期工作了!由于我只需要少数几个测试 运行,而且它们非常快,我可以接受并行性的损失!
您不能模拟 System
和其他系统 classes。这通常就是为什么您创建像 SystemCaller
class 这样的包装器的原因,它只包含不可测试的逻辑,并且您可以模拟它们在代码中的使用位置。
更多信息在这里:https://github.com/powermock/powermock/wiki/Mock-System
您可以在测试后尝试 PowerMockito.doCallRealMethod().when(System.class);
(@After 或 @AfterClass),它应该会重置 System.class 的 mock。
有一个名为 System Rules 的微型库可以帮助模拟系统 类。使用就这么简单
@Rule
public final ProvideSystemProperty myPropertyHasMyValue
= new ProvideSystemProperty("MyProperty", "MyValue");
Class 测试中:
public class SystemCaller {
public String callSystem() {
return System.getenv("test-this");
}
}
测试 1:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemCaller.class, System.class})
public class SystemTestOne {
@Before
public void start() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("test-this")).thenReturn("hello-one");
}
@After
public void stop() {}
@Test
public void verifySystemTestOne() throws Exception {
assertThat(new SystemCaller().callSystem(), is("hello-one"));
}
}
测试 2:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemCaller.class, System.class})
public class SystemTestTwo {
@Before
public void start() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("test-this")).thenReturn("hello-two");
}
@After
public void stop() {}
@Test
public void verifySystemTestTwo() throws Exception {
assertThat(new SystemCaller().callSystem(), is("hello-two"));
}
}
如果单独 运行,则每个测试都会自行通过。但是,当我 运行 all 测试时,测试失败。错误各不相同。有时,断言期望 hello-two
,但得到 hello-one
。在其他时候,callSystem()
只是 returns null
!
这里有设置问题吗?或者,这是因为我正在模拟导致问题的 static
方法(在本例中为 System
class)吗?
我的依赖项:
"org.apache.commons" % "commons-lang3" % "3.5" ::
"com.squareup.okhttp3" % "okhttp" % "3.6.0" ::
"com.google.code.gson" % "gson" % "2.8.0" ::
"com.novocode" % "junit-interface" % "0.8" % "test->default" ::
"junit" % "junit" % "4.12" % "test" ::
"org.hamcrest" % "hamcrest-core" % "1.3" % "test" ::
"org.hamcrest" % "hamcrest-library" % "1.3.RC2" % "test" ::
"com.squareup.okhttp3" % "mockwebserver" % "3.8.0" % "test" ::
"org.powermock" % "powermock-core" % "1.6.6" % "test" ::
"org.powermock" % "powermock-api-mockito" % "1.6.6" % "test" ::
"org.powermock" % "powermock-module-junit4" % "1.6.6" % "test" ::
更新 1:
好的,@kevin-welker 的建议使用 EnvironmentVariables
确实奏效了。但是,我看到一个奇怪的问题,当我 运行 来自 Intellij IDEA 的 JUnit 测试(使用 JUnit 运行 配置 )时,一切正常,但是当我 运行 他们通过 sbt
(通过 ./sbt test
)他们失败了同样的错误 :(.
我正在利用 https://github.com/sbt/junit-interface 来 运行 这些测试,但似乎无法让它们发挥作用。
更新 2:
好的!感谢 @kevin-welker 和 @stefan-birkner,我让测试按预期工作了!由于我只需要少数几个测试 运行,而且它们非常快,我可以接受并行性的损失!
您不能模拟 System
和其他系统 classes。这通常就是为什么您创建像 SystemCaller
class 这样的包装器的原因,它只包含不可测试的逻辑,并且您可以模拟它们在代码中的使用位置。
更多信息在这里:https://github.com/powermock/powermock/wiki/Mock-System
您可以在测试后尝试 PowerMockito.doCallRealMethod().when(System.class);
(@After 或 @AfterClass),它应该会重置 System.class 的 mock。
有一个名为 System Rules 的微型库可以帮助模拟系统 类。使用就这么简单
@Rule
public final ProvideSystemProperty myPropertyHasMyValue
= new ProvideSystemProperty("MyProperty", "MyValue");