Mocking System class method using testng, mockito and powermock - mockito

I am currently writing tests to a legacy code which uses a function System.getenv("some_environment_variable")
I get a problem when I try to mock these variables by using mockito and powermock (used under testng framework)
What I did so far was
#BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("hello")).thenReturn("world");
}
#Test
public void test() {
assertEquals(System.getenv("hello"), "world");
}
But when I tried to run the code above i get the following error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
inside when() you don't call method on mock but on some other object.
So Iv'e read and saw that this error raised when trying to mock a method with mocking the class itself, but this is not the case here.

After toying around with this for quite sometime, here's how I managed to do it.
In a nutshell, in order to get powermockito and TestNG to work with each other you have to do the following (quoting from the blog post whose link is shared below so that the answer is complete and will be useful even if the blog is not available at a later point in time)
Configure TestNG to use the PowerMock object factory : You can do this either via the attribute object-factory in your <suite> tag of your suite xml or via an #org.testng.annotations.ObjectFactory annotated method which returns the powermock's implementation of TestNG interface org.testng.IObjectFactory viz., org.powermock.modules.testng.PowerMockObjectFactory (or) by extending org.powermock.modules.testng.PowerMockTestCase
Use #PrepareForTest to prepare your static class for being mocked by PowerMockito
Please refer to this blog for more details.
Here's a working sample:
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.IObjectFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.ObjectFactory;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
#PrepareForTest(System.class)
public class SampleTestClass {
#BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("hello")).thenReturn("world");
}
#Test
public void test() {
assertEquals(System.getenv("hello"), "world");
}
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
}
I used the below dependencies for creating this sample
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>

There is another JUnit library which may help you: system-rules, which will allow you to -- among other things -- set and restore environment variables. It is used in conjunction with JUnit #Rules

Related

Using mockito any() throws java.lang.IllegalAccessError: class org.mockito.Matchers tried to access private method

I'm facing the exception
java.lang.IllegalAccessError: class org.mockito.Matchers tried to access private method 'void org.mockito.internal.progress.ThreadSafeMockingProgress.()' (org.mockito.Matchers and org.mockito.internal.progress.ThreadSafeMockingProgress are in unnamed module of loader 'app')
at org.mockito.Matchers.(Matchers.java:107)
when I try to use the matcher any() in mockito when() stub call. The class argument type is for "NewOrder" from the binance spot java library here
I'm trying to do
when(mockBinanceApiRestClient.newOrder(any(NewOrder.class))).thenReturn(buyOrderResp);
mocking the BinanceApiRestClient.
The any() and when() are static imports from org.mockito.Mockito.
This is such a nightmare why it wouldn't work. Any help is much appreciated.
Looks like you have two conflicting versions of Mockito on your classpath.
ThreadSafeMockingProgress was converted to a singleton back in 2016, and its constructor was changed to private.
On the other hand, you seem to be using org.mockito.Matchers,
which was deprecated for a long while and finally removed in Mockito 4.x
I also faced similar issue when we used below dependency -
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
<scope>test</scope>
</dependency>
we had below import statements which were causing IllegalAccess exception
import static org.mockito.Matchers.any;
I replaced Matchers with ArgumentMatchers as below -
import static org.mockito.ArgumentMatchers.any;
This resolved the issue.

Practical use of metaprogramming

I started to learn metaprogramming. So far I used it to read annotations in Java and create sql statements based on given class but I don't see any practical use in it. Can you give me an example where and how you used it in your programs?
Annotating a method to be recogonized as a unit test.
import static org.junit.jupiter.api.Assertions.assertEquals;
import example.util.Calculator;
import org.junit.jupiter.api.Test;
class MyFirstJUnitJupiterTests {
private final Calculator calculator = new Calculator();
#Test
void addition() {
assertEquals(2, calculator.add(1, 1));
}
}
Note that the annotation here #Test exists as a flag. When the test runner launches, it registers a listener for annotated methods, and if it encounters an annotated method that is annotated with the Test annotation interface, it will register that test in the "list of tests to run"
See https://junit.org/junit5/docs/current/user-guide/ for more details.
There are many examples of annotations in the wild. This is just but one of them.

Cucumber-serenity not inject Steps

I´m using cucumber-selenium to run some integration tests. I manage to create the feature file and the Test class. But once that I´m in my Give method I see that the ScenarioSteps(ProjectMemberSteps) class that I define to talk with the object page is null.
I was expecting to be injected like JBehave does.
public class OrderTest extends StepsLibrary {
#Steps ProjectMemberSteps projectManager;//This one is null
#Before
public void beforeScenarios() throws Exception {
initializeDemoUIServer();
}
#Given("I open the login page")
public void openLoginPage(){
projectManager.openLoginPage();
}
}
This is the Scenario runner class for the test
/**
* Serenity story for login.
*/
#RunWith(CucumberWithSerenity.class)
#CucumberOptions(features="src/test/resources/features/order/order.feature",
glue = Order.BEHAVIOUR_PACKAGE)
public class Order {
public static final String BEHAVIOUR_PACKAGE = "com.behaviour.steps.serenity";
}
This is class ProjectMemberSteps is under steps/serenity/ as the documentation suggest.
I´m using Maven, and the libraries that I´m using are
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-junit</artifactId>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>core</artifactId>
<version>1.0.47</version>
</dependency>
Anyway this particular test I´m running with the IDE and not through Maven, but I was expecting that "ProjectMemberSteps" would be inject as JBehave use to do.
Any idea what´s wrong?
Regards.
I am also a newbie. I don't see any problem with your OrderTest.java class except it is unnecessarily extending a class called StepsLibrary. In Java-Cucumber, I don't extend any other class. Only exception is When
StepDefinition file(your OrderTest.java) delegates method calls to xxxxSteps.java class and which in turn delegates to xxxPageObject.java (which MUST extend PageObject class from Serenity import net.serenitybdd.core.pages.PageObject;)
I assume Before annotation is to repeat a scenario. Instead another alternative is Background keyword to be used in the feature file itself. I don't claim any advantage with this though.
Per me, Your Test Runner class should only give the package in which xxxxStepDefinitions.java resides, simply like glue = {"stepdefinitions"}, curly braces are optional I believe.
The rest looks perfectly OK to me. Including defining
#Steps ProjectMemberSteps projectManager;
Try one more time.

exclude metaclass properties for groovy model classes in swagger

How do we exclude metaclass properties in model for "groovy" classes as Response? I have a Jax-Rs resource which returns a groovy object annotated with swagger #ApiModel.
I see too many groovy specific attributes in swagger ui. How do I exclude it from serialization?
#EqualsAndHashCode
#Document(collection = 'MongoCollection')
#CompileStatic
#ToString
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
#ApiModel(value = "Represents a document from mongo collection")
class Foo {
..
..
}
It seems to be using Jackson for pogo-json serialization? How do annotate my groovy class to exclude metaclass properties from getting into json serialized string?
I tried using JsonIgnoreProperties annotation but it didnt help.
#JsonIgnoreProperties(ignoreUnknown = true, value = ["MetaClass","MetaMethod"])
If using springfox, see springfox issues 752, found a way to resolve this :
docket.ignoredParameterTypes(groovy.lang.MetaClass.class)
A code example is:
#Configuration
public class SpringFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.ignoredParameterTypes(groovy.lang.MetaClass.class)
.select()
.apis(RequestHandlerSelectors.any())
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.build();
}
}
This could be a bug in swagger as per https://github.com/wordnik/swagger-core/issues/519.
I switched from groovy to java classes for model objects to proceed as of now. Will work on creating a test for this issue when I get time.
https://springdoc.org/#groovy-support
Including this dependency with the springdoc-openapi-ui dependency will resolve the issue in the newer versions.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-groovy</artifactId>
<version>1.6.13</version>
</dependency>
Upgrading Swagger to a version >= 1.3.5 should resolve this.

Mockito methods are not accessible

I have mockito setup on my project with this maven lines:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
I have no problems to use the #Mock annotation but I can't access and use mockito methods like:
when(someMock.someMethod()).thenReturn();
Eclipse just does not recognize them.
Please help.
Try calling Mockito.when(foo.getBar()).thenReturn(baz) and Mockito.verify(foo).getBar(), which won't rely on static imports. Unlike the #Mock annotation, which is technically a class, when and verify are static methods on the Mockito class.
Once you have that working, then try the static imports to which David alluded:
import static org.mockito.Mockito.when; // ...or...
import static org.mockito.Mockito.*; // ...with the caveat noted below.
This will then allow you to use Mockito.when without specifying the Mockito class. You can also use a wildcard, as so, but per this SO answer the Java docs recommend using wildcards sparingly--especially since it can break if a similarly-named static method is ever added to Mockito later.
Adding import org.mockito.*; is insufficient because that adds all classes in the org.mockito package, but not the methods on org.mockito.Mockito.
For Eclipse in particular, you can add a static import by putting the cursor on the when part of Mockito.when and pressing Control-Shift-M ("Add import"). You can also add org.mockito.Mockito to your Favorites (Window > Preferences > Java > Editor > Content Assist > Favorites > New Type) so that all Mockito static methods show up in your Ctrl-Space content assist prompt even if you haven't imported them specifically. (You may also want to do this for org.mockito.Matchers, which are technically available on org.mockito.Mockito via inheritance, but may not show up in Eclipse for that reason.)
Kotlin syntax - dont forget the ` ` backticks:
import org.mockito.Mockito.`when`
`when`(someMock.someMethod()).thenReturn();

Resources