How to use MockMvcResultMatchers.jsonpath to do test? - mockito

I am writing some tests for spring mvc application.
I got the response as follows.
-> curl -X POST -H"Content-type:application/json; charset=utf-8" localhost:8080/mvc/addBlacklist.do -d '{"id": "1", "imsi": "test"}'
{"id":0,"imsi":"18192729090","name":"xiaoshao","monitors":null}
But when my test like this one.
Blacklist blackList = new Blacklist();
blackList.setId(0);
blackList.setImsi("18192729090");
blackList.setName("xiaoshao");
when(blacklistService.add(any())).thenReturn(blackList);
mockMvc.perform(post("/addBlacklist")
.content(TestUtil.convertObjectToJsonBytes(blackList))
.contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(status().is(200))
.andExpect(jsonPath("$.imsi", is("xiaoshao")));
It emit an exception like this.
java.lang.NoClassDefFoundError: com/jayway/jsonpath/InvalidPathException
at org.springframework.test.web.servlet.result.JsonPathResultMatchers.<init>(JsonPathResultMatchers.java:53)

You are missing a dependency for the test. Add this to your maven pom.
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>

Use this:
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

Related

Cucumber No features found with JUnit5

I am trying to setup Cucumber in my project. I am following the same configuration from my previous projects but I still have issues with running the tests. Now I am starting to suspect that the issue might be that this project is using JUnit 5 instead of 4. I have added junit4 to the build options as well to be able to execute the #RunWith annotation with jUnit4, but I still get the same error ( No features found at classpath ) .
The runner class is as follows:
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.CucumberOptions.SnippetType;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(features = "classpath:resources", plugin = {"pretty", "html:target/reports/cucumber/html",
"json:target/cucumber.json", "usage:target/usage.jsonx",
"junit:target/junit.xml"}, snippets = SnippetType.CAMELCASE)
public class TestCucumberRunner {
}
The structure of the folders is following:
Here is the pom configuration:
As far as I can see, the #RunWith annotation is imported from junit4 and not 5, so why is this issue happening?
I also tried adding the feature file in the same folder with the runner, as well as adding the exact path in the feature option, but still the same error.
You can run Cucumber tests with Junit 5 and via maven. I searched a lot before finding the right configuration.
The important steps :
add maven-surefire-plugin in you plugins pom, so cucumber tests can bu run from mvn test
use the same structure for features in your test resources as your cucumber java steps (if your test class is in com.example.usescase, locate your feature in resources/com/example/usecase )
add cucumber launcher on the root folder of your java tests. I can be annotated with just #Cucumber
Courtesy to https://github.com/bonigarcia , I really found how to make it work thanks to its repository https://github.com/bonigarcia/mastering-junit5/tree/master/junit5-cucumber
With Junit5, you just need to write runner like below :
#Suite
#SelectClasspathResource("Features Folder")
public class Runner {
}
For using tags, you can put the tags properties in junit-platform.properties.
You can refer for pom dependencies - https://github.com/cucumber/cucumber-java-skeleton/blob/main/pom.xml
I was facing a lot of issues. I followed above and could run my cucumber tests with Junit5 without any issues.
There might be some problems with the step definitions as well (cann't tell exactly by looking at the info), looks like that Cucumber cannot find your feature file step definitions.
please have a look on cucumber documentation
You need to specify the path to your step definitions (glue path) correctly.
Usually cucumber jvm will search in the package (or sub-packages) of the runner class. However, you can also mention explicitly by the following way:
#CucumberOptions(glue = ["", "", ""])
Setting up Cucumber with JUnit 5 has not been documented very well (yet). The trick is to use the cucumber-junit-platform-engine as described in https://cucumber.io/docs/cucumber/api/.
For example:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>6.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>6.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>6.6.1</version>
<scope>test</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<configurationParameters>
cucumber.plugin=pretty,html:target/site/cucumber-pretty.html
cucumber.publish.quiet=true
cucumber.publish.enabled=false
</configurationParameters>
</properties>
</configuration>
</plugin>
</plugins>
</build>
Now use the maven-surefire-plugin to inject Cucumber parameters, since the 'old' JUnit 4 #CucumberOptions annotation won't have any effect anymore.
More Cucumber configuration options can be found here: https://github.com/cucumber/cucumber-jvm/tree/main/junit-platform-engine#configuration-options
Your Java entry point for your Cucumber tests will now look like this:
#RunWith(Cucumber.class)
public class BDDEntryPointTest {
/*
Entry point class for Cucumber test.
It will automatically scan for
1. *.feature files in src/test/resources
2. Step definitions in java files under in src/test/java
*/
}
I had similar issues with junit5 and I got it resolved by removing these three dependencies from pom
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
and by keeping these ones
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
and then your runner class will be just
#Cucumber
public class AcceptanceIT {
}
and step defs would be . No #Test annotations
#Given("I log {string}")
public void logSomething(String teststr ) {
System.out.println("sample text:"+ teststr);
}
Note I am using maven-failsafe here . The runner class name might different if you use other plugin like maven-surefire or use any other mechanism. Here is my maven-failsafe config
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<failIfNoTests>false</failIfNoTests>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
</plugin>

Cucumber rerun failed tests and cocatenate results using a testNG runner for cucumber 4.x

I am trying to execute a 2nd round of running only the failed scenarios in order to avoid false alarms because of environment/network/test unstabilities.
I am wondering if there is way to run only a maven command that will perform the following:
1. run all the scenarios that my runner includes in its configuration
2. create the cucumber.json report for this run
3. create a list of the failed scenarios
4. run the list of the failed scenarios
5. change the result of the report created in 1rst run depending on the results of failed tests in 2nd run, so that at the end, only the scenarios that failed in both runs are marked as failed and also there are no duplicates in the final report for those tests that failed at 1rst run (i.e. 2nd run overides the result of 1st run).
I am using cucumber 4.4.0 and testNG runner.
I have tried to use #ExtendedCucumberOptions (http://mkolisnyk.github.io/cucumber-reports/extended-cucumber-runner) and the 1rst run was ok, but the 2nd run was never happened, throwing the following exception:
"Method public void com.github.mkolisnyk.cucumber.runner.ExtendedTestNGRunner.feature(cucumber.api.testng.CucumberFeatureWrapper) requires a #DataProvider named : feature"
I found this issue:
https://github.com/mkolisnyk/cucumber-reports/issues/138
So, it seems that this cucumber-reports library does not support later versions of cucumber and I cannot use #ExtendedCucumberOptions that seemed to provide exactly what I need.
===> My maven dependecies include:
<dependency>
<groupId>com.github.mkolisnyk</groupId>
<artifactId>cucumber-runner</artifactId>
<version>1.3.4</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.4.0</version>
</dependency>
===> And my runner class :
package runners;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
import org.testng.annotations.DataProvider;
#CucumberOptions(
features = {"src/test/resources/features/"},
glue = {"stepDefinitions"},
tags = {"#magic"},
plugin = {
"pretty"
, "html:target/cucumber"
, "json:target/cucumber/cucumber.json"
, "rerun:target/cucumber/failedTests.txt"
},
monochrome = false
)
public class AreaRunner extends AbstractTestNGCucumberTests {
#Override
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
}
Is there any solution other than #ExtendedCucumberOptions?
The reason the 2nd run never happened is because Retry functionality is applicable for JUnit runner only, as per https://github.com/mkolisnyk/cucumber-reports/issues/167.
Try https://github.com/prashant-ramcharan/courgette-jvm - it has the ability to rerun failing tests similarly to ExtendedCucumberOptions, but this one contains the new Cucumber already.

PIT-Cucumber plugin not finding scenarios in feature files

Try to institue PIT Mutation testing in a enterprise project. Got it to do existing JUNit tests, but we also have a lot of Cucumber tests that need to be part of the metric. Added pit-cucumber plugin to the maven project, but the output is no scenarios found. Not sure if there is some secret in the config of the plugin that I can't see.
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.4.7</version>
<configuration>
<testPlugin>Cucumber</testPlugin>
<targetClasses>
<param>org.tiaa.srk.eligibility.*</param>
</targetClasses>
<targetTests>
<param>org.tiaa.srk.eligibility.EligibilityTestRunnerIT</param>
</targetTests>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>com.github.alexvictoor</groupId>
<artifactId>pitest-cucumber-plugin</artifactId>
<version>0.8</version>
</dependency>
</dependencies>
</plugin>
I get this output:
INFO : Sending 0 test classes to minion
Make sure you're using Cucumber version 4.20 jars with pitest-cucumber-plugin 0.8
Everything else looks good. You may not need to specify targetClasses and targetTests.

PhantomJS driver is not getting invoked while using WebDriverManager for my java code

I have been using WebDriverManager to manage drivers for my class file which in turn is used extended to other class files for testing using Selenium.
I am using maven to do the builds, below is the content of my pom.xml file :
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>3.1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
And below is the class file that I am using to invoke the drivers :
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeTest;
import io.github.bonigarcia.wdm.WebDriverManager;
import io.github.bonigarcia.wdm.PhantomJsDriverManager;
public abstract class GetDriver {
// declare driver
public WebDriver driver;
// Assign the driver
#BeforeTest
public void WebdriverSetUp() {
WebDriverManager.phantomjs().setup();
driver = new PhantomJsDriver();
}
}
Now the problem is that whenever I try to add the phantomjs driver using the below two lines :
WebDriverManager.phantomjs().setup();
driver = new PhantomJSDriver();
It gives me the error, "PhantomJSDriver cannot be resolved to a type". Eclipse suggests me to do any of the below fix :
Create class 'PhantomJSDriver'
Change to 'WebDriver' (org.openqa.selenium)
"Change to 'PhantomJsDriverManager' (io.github.bonigarcia.wdm)"
When I try selecting the third fix which is to change to PhantomJsDriverManager, another error pops up
Type mismatch: cannot convert from PhantomJsDriverManager to WebDriver
For the above error again, Eclipse suggests two fixes :
Add cast to 'WebDriver'
Change type of 'driver' to 'PhantomJsDriverManager'
When I select the second option from above the code changes to
public abstract class GetDriver {
// declare driver
public PhantomJsDriverManager driver;
// Assign the driver
#BeforeTest
public void WebdriverSetUp() {
WebDriverManager.phantomjs().setup();
driver = new PhantomJsDriverManager();
}
}
After the above change I now get the error, "The constructor PhantomJsDriverManager() is not visible".
This issue is happening just for the PhantomJs driver. I tried with chrome driver and it worked like a charm. Please help me as to how can I use webdrivermanager so that I can PhantomJS driver to be used for headless execution of my Selenium code.
I had to move away from using the WebDriverManager for PhantomJS and instead used chrome driver with headless chrome. That fixed the issues I was facing, and finally I was able to do my testing via Jenkins without any issues.
I had same issue so i decide to go with ChromeOptions class instead of PhantomJS driver by setting the value of addArguments as --headless like below:
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
options.addArguments("--disable-gpu");
driver = new ChromeDriver(options);

Using PowerMock with Spock

I have a class with a few static methods.I need to Mock these static methods. I know PowerMock does this,but I was not able to find any tutorials/materials that shed some light on "Spock+PowerMock" integration. I prefer Spock to Junit,hence the conundrum. Is there a way of getting these 2 frameworks to play ball?Any help is much appreciated.Sample code,even more so.
Update: Current Status of the Approach
Spock behaving weirdly
I was stuck here for a while too. After searching for hours, I saw this github repo: https://github.com/kriegaex/Spock_PowerMock.
I tried adding a PowerMockRule which essentially enabled me to use PowerMock together with Spock. I had to add these dependencies. Version is at 1.5.4
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-rule</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-classloading-xstream</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
My class looks like this:
import org.junit.Rule
import org.mockito.Mockito
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.rule.PowerMockRule
import spock.lang.Specification
#PrepareForTest([SomeStaticClass.class])
public class FlightFormSpec extends Specification {
#Rule PowerMockRule powerMockRule = new PowerMockRule();
def "When mocking static"() {
setup :
PowerMockito.mockStatic(SomeStaticClass.class)
when :
Mockito.when(SomeStaticClass.someStaticMethod()).thenReturn("Philippines!");
then :
SomeStaticClass.someStaticMethod() == "Philippines!"
}
}
Here is another resource: https://github.com/jayway/powermock/wiki/powermockrule
There is no special integration; your best bet is to try and use PowerMock "as-is". From what I remember, PowerMock used to have problems with Groovy, and I don't know if this has been solved. And if I'm not mistaken, PowerMock rewrites the byte code of test classes, so the next question is if it works with Spock. Let us know what you find.
Since Powermock Version 1.6.0, powermock allows the delegation of the test runner.
This allows the wrapping of the Spock test runner (Sputnik) within the PowerMock test runner framework. Sputnik will then start the test case specifications, and still allow the use of the PowerMock framework.
With JUnit4 and Powermock, I use the following template for accessing static classes.
The test class:
package mypackage;
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 org.powermock.modules.junit4.PowerMockRunnerDelegate
import org.spockframework.runtime.Sputnik
import spock.lang.Specification
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(Sputnik.class)
#PrepareForTest([MyStaticMethodClass.class])
class MyTestForClassTest extends Specification {
def myStaticMethodClass
def setup() {
PowerMockito.mockStatic(MyStaticMethodClass.class)
myStaticMethodClass= Mock(MyStaticMethodClass)
PowerMockito.when(MyStaticMethodClass.getInstance()).thenReturn(myStaticMethodClass)
}
#Unroll
def "#TestCase policy RF210 triggered"() {
given: "a product list for the policy"
myStaticMethodClass.someInstanceMethod() >> "my return value"
classUnderTest = new ClassUnderTest()
...
The dependencies
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.3-groovy-2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>

Resources