#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticMethodsHolder.class)
public class MockNTestStaticMethodsHolder {
#Rule public PowerMockRule rule = new PowerMockRule();
#Test public void staticSvcClientMethod () {
// blah blah blah
mockstatic (StaticMethodsHolder.class);
expect (StaticMethodsHolder.TomBradyIsStillTheBest()).andReturn(UNQUESTIONABLY);
expect (StaticMethodsHolder.NEPatriotsStillTheBest()).andReturn(MAYBE);
expect (StaticMethodsHolder.NEPatriotsLiiWereIdiots()).andReturn(TOTALLY);
expect (StaticMethodsHolder.NEPatriotsWinsLiii()).andReturn(RU_KIDDING_ME);
}
}
Maven dependencies/properties in the following order:
powermock-version 1.6.6
easymock-version 3.4
easymock
powermock-module-junit4
powermock-api-easymock
powermock-module-junit4-rule-agent
(removing this causes constructor issues)
powermock-module-junit4-rule
(removing this dependency has no effect)
powermock-classloading-xstream
Runtime error:
java.lang.IllegalStateException PowerMockRule can only be used
with the system classloader but was loaded by
org.powermock.core.classloader.MockClassLoader.
PowerMock is biting is own tail. It wants to use its own classloader, but the JVM says PowerMockRule must be loaded by system's.
What can I do to resolve this?
You are already using the PowermockRunner, you do not need to use the rule.
https://github.com/powermock/powermock/wiki/powermockrule
if you were using a different runner while requiring Powermock functionality that is the use case for the Rule.
Related
I use JUnit 5 and I have a simple abstract class that serves as a test provider for its child classes:
abstract class TestProvider {
#TempDir
#SuppressWarnings("unused")
Path tempDir;
protected void helpWithSomething() {
// let's pretend it actually does something
}
}
SonarQube complains because of the RSPEC-2924 rule that states the following:
This rule also applies to the JUnit 5 equivalent classes: TempDir, and TestInfo.
Surprisingly, the page offers a solution without any creation of such temporary folder, either using #Rule with older versions of JUnit or with #TempDir as of JUnit 5. Note the following snippet only removed non-compliant line with no alternative and compliant solution, which is kind of ridiculous.
public class ProjectDefinitionTest {
#Test
public void shouldSetKey() {
ProjectDefinition def = ProjectDefinition.create();
def.setKey("mykey");
assertThat(def.getKey(), is("mykey"));
}
}
I would expect at least a relevant compliant solution as this completely breaks the gist of the test. Note the tempDir is actually accessed with the child classes.
What is a correct and compliant usage of #TempDir according to SonarQube? Although I am aware of using a different suppression (#SuppressWarnings("squid:S2924")), I would like to know a compliant solution.
I am using
#Rule
public PowerMockRule rule = new PowerMockRule();
in one of my test file. Now when I am removing this part of code several test cases starts failing which are in different folders and having no direct relationship with this file.
What could be the problem?
Refer to the below wiki link for more details.
Technically, instead of using #RunWith(PowerMockRunner.class) , you can use PowerMockRuleas shown in the below example.
So, when you remove PowerMockRule, your tests are gonna fail because you will not have #RunWith(PowerMockRunner.class) in your tests.
https://github.com/powermock/powermock/wiki/powermockrule
Bootstrapping using a JUnit Rule
Feature avaliable since PowerMock 1.4 Since version 1.4
It's possible to bootstrap PowerMock using a JUnit Rule instead of
using the PowerMockRunner and the RunWith
annotation. This allows you to use other JUnit runners while still
benefiting from PowerMock's functionality. You do this by specifying:
With PowerMockRule
#PrepareForTest(X.class);
public class MyTest {
#Rule
PowerMockRule rule = new PowerMockRule();
// Tests goes here
...
}
Without PowerMockRule
#RunWith(PowerMockRunner.class)
#PrepareForTest(X.class);
public class MyTest {
// Tests goes here
...
}
I don't have the newest version of TestNG, and I have option to add #Test on constructor, java docs
#Target({METHOD, TYPE, CONSTRUCTOR})
public #interface Test {
I didn't find any clue on usage in docs or searching online
#Test Marks a class or a method as part of the test.
When/Why #Test can be define on constructor? is it for internal purposes only?
I saw that CONSTRUCTOR was removed in latest TestNG version, but I didn't find why.
See issue "Remove irrelevant "targets" for TestNG annotations": The target CONSTRUCTOR had no functionality in older versions, because constructors were not seen as test methods. That's why the target was removed later.
I'm using WireMock in my tests and have such a line of code:
#Rule
public WireMockRule wireMockRule = new WireMockRule(8080);
I want to switch to JUnit 5. So I added the next dependency (using Gradle):
testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1')
But there are no suggestions when I'm trying to import #Rule annotation.
Do I need to add another module of JUnit dependency? Or are rules not supported in JUnit 5? If not, how can I replace #Rule annotation to make tests work again?
In a general way, what you did with #Rule and #ClassRule in JUnit 4 should be done with #ExtendWith and Extension that associated provide a very close feature in JUnit 5.
It works as standards JUnit lifecycle hooks but that it is extracted in a Extension class. And similarly to #Rule, as many Extensions as required may be added for a test class.
To handle the issue you have several possible approaches among :
keep the JUnit 4 way (JUnit 5 owns the JUnit Vintage part that allows to execute JUnit 3 or 4 tests).
rewrite the #Rule as an Extension.
do the actual processing done by WireMockRule (start the server, execute your tests and stop the server) in each test of class with #BeforeEach and #AfterEach hook methods.
use a third library that implements the equivalent of WireMockRule in the JUnit 5 Extension way such as https://github.com/lanwen/wiremock-junit5
Note that your issue already discussed in the JUnit 5 Issues.
JUnit 4 annotations #Rule and #ClassRule do not exist in JUnit 5. Basically there is a new extension model that can be used to implement extensions with the same functionality. These extensions can be used with the #ExtendWith annotation.
There is a limited migration support for a subset of JUnit 4 rules in the junit-jupiter-migrationsupport module. Unfortunately, it's only limited to subclasses of ExternalResource and Verifier.
Before wiremock has official support for JUnit you have some workarounds:
Run JUnit 4 tests side by side with JUnit 5 tests with the junit-vintage-engine.
Start and stop the server yourself in the test code.
Use a 3rd party extension like wiremock-junit5 or wiremock-extension.
There is now official support for JUnit 5 Jupiter from WireMock 2.31.0.
Docs here: http://wiremock.org/docs/junit-jupiter/
The https://github.com/webcompere/java-test-gadgets project lets you solve this in a couple of ways.
You can use its support for JUnit 4 rules via the DangerousRuleAdapter - which will attempt to turn any JUnit 4 rule into a Plugin:
#ExtendWith(PluginExtension.class)
public class DangerousRuleAdapterExampleTest {
#Plugin
private DangerousRuleAdapter<WireMockRule> adapter =
new DangerousRuleAdapter<>(new WireMockRule());
#Test
void theTest() {
// use wiremock rule here
WireMockRule rule = adapter.get();
}
The rule adapters cannot work with rules that inspect the test class or the test method, but make a good attempt at running the rule.
There's also support for running a rule around some code:
TemporaryFolder temporaryFolder = new TemporaryFolder();
// let's use this temp folder with some test code
executeWithRule(temporaryFolder, () -> {
// here, the rule is _active_
callSomethingThatUses(temporaryFolder.getRoot());
});
And you can easily create your own new JUnit 5 plugin by using the PluginExtension and TestResource.of
#ExtendWith(PluginExtension.class)
class TestResourceIsActiveDuringTest {
private WireMockServer server;
#Plugin
private TestResource someResource = TestResource.from(() -> server.start(),
() -> server.stop());
From the JUnit 5 user guide:
#Rule and #ClassRule no longer exist; superseded by #ExtendWith and #RegisterExtension. See also "Limited JUnit 4 Rule Support".
However, as pointed out by Tom, WireMock has full JUnit Jupiter support since version 2.31.0:
// New JUnit 5 extension
#WireMockTest
class DeclarativeWireMockTest {
#Test
void test_something_with_wiremock(WireMockRuntimeInfo wmRuntimeInfo) {
// The static DSL will be automatically configured for you
stubFor(get("/static-dsl").willReturn(ok()));
// Instance DSL can be obtained from the runtime info parameter
WireMock wireMock = wmRuntimeInfo.getWireMock();
wireMock.register(get("/instance-dsl").willReturn(ok()));
// Info such as port numbers is also available
int port = wmRuntimeInfo.getHttpPort();
// Do some testing...
}
}
For more information, please refer to the corresponding docs.
I have a unit test that attempts to create a SQLException to simulate a database error. In SQLException's constructor, there is a call to DriverManager, which has a static initialization block. I figured that I could suppress the static block with this type of setup:
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor({"java.sql.DriverManager"})
public class StaticTest
{
#Test
public void testStaticSuppress() throws Exception
{
SQLException ex = new SQLException();
expect(...).andThrow(ex);
}
}
When I run the test, the static block in DriverManager is still called. What am I doing wrong?
Clarifications
I am running Powermock 1.5 - I was under the impression that using v1.5 allows me to mock system classes
When DriverManager runs it's static initialization block, I get this exception:
Oct 15, 2013 1:06:24 PM oracle.jdbc.driver.OracleDriver registerMBeans
WARNING: Error while registering Oracle JDBC Diagnosability MBean.
java.lang.LinkageError: loader constraint violation: when resolving method "java.lang.management.ManagementFactory.getPlatformMBeanServer()Ljavax/management/MBeanServer;" the class loader (instance of org/powermock/core/classloader/MockClassLoader) of the current class, oracle/jdbc/driver/OracleDriver, and the class loader (instance of ) for resolved class, java/lang/management/ManagementFactory, have different Class objects for the type javax/management/MBeanServer; used in the signature
I realize that I could make a mock of SQLException and never instantiate it directly. I would rather not go that route since it would mean updating 91 different unit tests. I asked the question because it looked like my code should work just fine according to the PowerMock docs.
I suspect (but I am not certain) that Powermock is unable to prevent the static initializer from running for classes that are loaded by the system or bootstrap classloader (like the jre classes including those of the package java.sql are).
After posting to the Powermock Google Group, I got this response:
You can mock, suppress methods, stub methods etc in these classes since powermock 1.2.5 but you cannot suppress static initializers.
See this page: Google Groups PowerMock Group
You need to add to the class: #PowerMockIgnore("javax.management.*")