Liferay 7 & JUnit : Mock Local Custom Local Service Util - junit

I'm trying to mock with powermockito my custom local service util, but i always get an error.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ServiceSubscriptionLocalServiceUtil.class})
public class CStreamTest {
#Before
public void setUp() throws NoSuchFieldException, IllegalAccessException {
.........
mockStatic(ServiceSubscriptionLocalServiceUtil.class);
.........
}
}
and i'm getting the following error :
java.lang.ExceptionInInitializerError
at sun.reflect.GeneratedSerializationConstructorAccessor4.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:19)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:47)
at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25)
at org.powermock.api.mockito.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:41)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:62)
at org.mockito.Mockito.mock(Mockito.java:1896)
at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMethodInvocationControl(DefaultMockCreator.java:108)
at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.doCreateMock(DefaultMockCreator.java:61)
at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMock(DefaultMockCreator.java:53)
at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.mock(DefaultMockCreator.java:40)
at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:62)
at com.e.c.stream.impl.test.CStreamTest.setUp(CStreamTest.java:50)
i add some parts of my pom.xml :
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.24.0</version>
<scope>test</scope>
</dependency>
<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-core</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
Any ideas ?
Thanks

Liferay's *LocalServiceUtil classes contain a bunch of static methods that just simplify the lookup of an actual service implementation. Given that you state you're on Liferay 7, you should just utilize the services themselves and rely on #Reference dependency management and injection in the code that uses them. This way you just need to mock a regular interface that is not loaded with some default implementation and lookup.
Another option is to test the implementation - and write tests for the code "above" the service, as well as its implementation. It's typically hard to write UI-layer code, e.g. portlets, in a test-driven fashion, where mocking isn't heavily dependent on the implementation of the service and the calling classes.

Normally services utility classes created by Service builder do not have a no arg constructor, not even a constructor for that matter.
But if you check the log you will see and this is your issue:
New instance of the class is created inside PowerMock.
java.lang.ExceptionInInitializerError at sun.reflect.GeneratedSerializationConstructorAccessor4.newInstance(Unknown Source)
After trying to create an instance for: ObjenesisBase....
Even though it has not constructors, services utils normally initialize static members, like a ServiceTracker.
You could create a bummy service impl or your code could use the service reference instead of the util, you could mock that guy. Several options here, even mocking methods that give you the service to give you a dummy service.
But in summary, you cannot just do:
mockStatic(ServiceSubscriptionLocalServiceUtil.class);
As this will create an instance, and that instance has static members that need to be initialized.

Related

Error:org.apache.commons.logging.LogFactoryjava.lang.NoClassDefFoundError for application build with micronaut-bom1.2.10, graal19.2.1 & aws-sdk2.10.56

Created an application using micronaut bom 1.2.10 version, along with software.amazon.awssdk:lambda:2.10.56 & software.amazon.awssdk:s3:2.10.56 dependencies which had functionality to retrieve data from s3 storage and used graal 19.2.1 to create a native image.
The native image is successfully created but when i try to access the endpoint it fails for below exception:
failed: org.apache.commons.logging.LogFactoryjava.lang.NoClassDefFoundError: org.apache.commons.logging.LogFactory
and series of exceptions with specifically while creating S3 client.
The exception also had failure at below point:
failed: Could not initialize class software.amazon.awssdk.http.apache.internal.conn.SdkTlsSocketFactoryjava.lang.NoClassDefFoundError: Could not initialize class software.amazon.awssdk.http.apache.internal.conn.SdkTlsSocketFactory
Code for S3Client :
S3Client s3Client = S3Client.builder().region(getRegion()).build();
build-native-image.sh
${GRAALVM_HOME}/bin/native-image --no-server -cp example-function-*-all.jar
-H:IncludeResources="git.properties"
-H:IncludeResources="logback.xml"
-H:IncludeResources="application.properties" \
So this issue was resolved by adding below configuration in build.gradle:
allprojects {
configurations {
all {
exclude(group = "commons-logging")
}
}
}
and in the dependencies added:
compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.30'
I hope this helps.
I faced the same issue, when running tests, with the exact same NoClassDefFoundError but when using AWS sts and secretsmanager libraries. I could actually get it to work by just including the jcl-over-slf4j dependency, while the error happened when using the slf4j-api dependency. I did not need to exclude commons-logging. Snippet of dependency in maven pom.xml that worked:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.17.89</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>secretsmanager</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sts</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
</dependencies>

Integration Test with Couchbase container

I am writing an integration test, which should use a couchbase container.
Using org.testcontainers.couchbase.CouchbaseContainer with
#Rule
public CouchbaseContainer couchbaseContainer = new CouchbaseContainer()
.withNewBucket(DefaultBucketSettings.builder()
.enableFlush(true)
.name("xxx").password("123456")
.quota(100)
.type(BucketType.COUCHBASE)
.build());
I get an error:
Caused by: com.couchbase.client.java.error.InvalidPasswordException: Passwords for bucket "xxx" do not match.
at com.couchbase.client.java.CouchbaseAsyncCluster$OpenBucketErrorHandler.call(CouchbaseAsyncCluster.java:651)
When I looked inside the container, I could see that bucket whose created without the user. (In order to be able to use that bucket, a user, with the same name must be created, and user's password is actually password to enter the bucket).
While not providing UserSettings, withNewBucket method generates user with all roles. I tried to add custome UserSettings, but the result was the same - user wasn't created.
Using
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>couchbase-client</artifactId>
<version>1.4.13</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>couchbase</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>jdbc</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>2.5.9</version>
</dependency>
Any help is appreciated.

Migration issue from Junit 4 to Junit 5

I am migrating my codebase from junit4 to junit5.I have used mockito in my testcase.Below are the different version that i am using for the dependency.
<junit.jupiter.version>5.2.0</junit.jupiter.version>
<junit.platform.version>1.2.0</junit.platform.version>
<org.mockito.version>1.10.19</org.mockito.version>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
I have used the annotation #RunWith(MockitoJUnitRunner.class) to run my mockito code.Replaced the same with #ExtendWith(MockitoExtension.class)
But when i run the test case i get the below error. Any suggestion to solve this issue. I suspect is there any dependency version issue which is causing this problem.
java.lang.NoClassDefFoundError: org/mockito/quality/Strictness
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at..
Thanks
-Sam
The JUnit5 MockitoExtension uses org.mockito.quality.Strictness so in order to use MockitoExtension you'll need to use a version of mockito-core which contains org.mockito.quality.Strictness. mockito-core:1.10.19 does not contain that class because that class was added in Mockito 2.x. So, in order to use MockitoExtension you'll need to use at least version 2.x of mockito-core.
The Mockito docs don't make this explicit but I suspect the expectation is that you'll use the same Mockito version for mockito-core and for mockito-junit-jupiter.
The following dependencies will allow you to use the JUnit5 MockitoExtension successfully:
<org.mockito.version>2.19.0</org.mockito.version>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${org.mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${org.mockito.version}</version>
<scope>test</scope>
</dependency>
I tried to use same version for mockito-junit-jupiter and mockito-core, but fails.
At last I init the mocks myself in #BeforeEach block.
#BeforeEach
private void setup() {
MockitoAnnotations.initMocks(this);
}
as a workaround.
Thanks for the response #glytching .With your input i was able to find the correct version dependency for me and it resolved my issue. Below is the version that i used to resolve the same.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.22.0</version>
<scope>test</scope>
</dependency>
Also i needed mockito-core => version 2.22.0. But above mentioned mockito-junit-jupiter comes with mockito core dependency internally.So no need to add that dependency.

Unsupported Media Type Jersey

I am using Maven and Jersey on Tomcat7 to build a web server, but I keep getting a 415 response. My request is made using Postman and Advanced Rest Client
My stubbed method:
#POST
#Path("/createuser")
#Consumes(MediaType.APPLICATION_JSON)
public Response createUser(UserInformation user){
return Response.ok().build();
}
Custom class:
package efile.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
#JsonInclude(Include.NON_NULL)
public class UserInformation {
private String id;
private String username;
private String password;
private String firstName;
private String lastName;
private String emailAddress;
/* getters and setters */
}
Request:
{myhost}/createuser
Headers:
accept: application/json
content-type: application/json
Request body:
{
"id":"1234567",
"userName":"qwer",
"password":"zxcv",
"firstName":"jasdfme",
"lastName":"qwetad",
"emailAddress": "qwet#gf4elk.com"
}
My dependencies:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>com.dropbox.core</groupId>
<artifactId>dropbox-core-sdk</artifactId>
<version>1.7.6</version>
</dependency>
<dependency>
<groupId>org.jvnet.mimepull</groupId>
<artifactId>mimepull</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.2.0</version>
</dependency>
Thanks.
On my side it was because I forgot to add
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.18</version>
</dependency>
after
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.18</version>
</dependency>
No warnings/errors at compilation but 415 Unsuported Media Type at runtime trying to consum JSON on Jersey 2.18 running on AppEngine
Hope it helps
If you are sending the 'Accept' header, you may also need to add the #Produces(MediaType.APPLICATION_JSON) annotation to your method, or, remove the Accept header from the request if you are not expecting a response body.
Edit:
Ok... After a bit of experimentation, I believe I have been able to reproduce your problem and find a solution.
I see from your pom file that you are using Jersey 1.17. I reproduced your problem using Jersey 1.18, but I suspect it is equally valid for 1.17. It appears that Jersey does not come with Jackson support built in, but Jackson must be installed as a provider. I've always used it with containers like Glassfish where the providers come pre-configured.
I was not able to make Jersey 1.18 work with the latest Jackson 2 libraries (under the com.fasterxml.jackson groupId) that you were pulling in with your pom.xml, but I was able to get it working with the older Jackson libraries when the groupId was still org.codehaus.jackson. It appears that Jersey 1.18 uses a class called com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy which looks specifically for a Jackson implementation in org.codehaus.jackson... So you might not be able to make the newer versions of Jackson work without upgrading to a newer version of Jersey.
Firstly, I added the XmlRootElement annotation to the UserInformation class. Jax-RS will serialize and deserialize JAXB objects and this annotation marks this class as a JaxB object. This required an additional dependency in the pom on the jaxb-api:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
Next, I removed all of the Jersey dependencies from your pom.xml file, and added a dependency on the jersey-server to give access to the necessary JaxRS annotations:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18</version>
<scope>provided</scope>
</dependency>
I then took a clean installation of Tomcat 7.0.52, and added the following jars to the CATALINA_HOME/lib directory:
asm-3.3.1.jar (Byte code manipulation used by Jackson)
jacksore-core-asl-1.9.13.jar (Includes the Jackson JSON Provider)
jersey-bundle-1.18.jar (The Jersey Implementation)
I found it necessary to add these jars to the Tomcat lib folder rather than include them in the project WAR file. I don't work with Tomcat much, so I don't recall the rules about exactly when it is necessary to place jars in the Tomcat lib directory vs. including them in the WAR file.
Following all of those steps I was able to go from getting the 415 Media Unsupported error to a 200 OK on the POST.
I hope this helps.
I was able to resolve the issue after modifying the dependencies in the pom.xml. I updated the jersey dependencies to 1.18.1 and added the fasterxml json provider dependency:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.1</version>
</dependency>
My guess is that it was just the json-provider dependency that resolved the issue.

Emma code coverage with JUnit and Powermock

I am using JUnit with Powermockito mocking.
I have to work on a CLI environment with maven or ant.
emma version: ema-2.0.5312
powermock version: powermock-mockito-1.5.1-full
junit version: junit-4.9
When I run junit through the following command, everything works find:
java org.junit.runner.JUnitCore some.package.ClassTest
However, when I used emma to check the code coverage:
java emmarun -cp $CLASSPATH -report txt org.junit.runner.JUnitCore some.package.ClassTest
I got the following error:
1) initializationError(some.pakage.ClassTest)
java.lang.ClassCastException: org.powermock.modules.junit4.PowerMockRunner cannot be cast to org.junit.runner.Runner
Other test classes without using powermock work fine.
Does anyone have some suggestion to this? thanks in advance.
while using powermock, you can not find out the coverage using Emma
See this discussion on developer's side
You can use MockitoJunitRunner and specify a rule to use PowerMock since Eclemma works along with MockitoJUnitRunner.
Something like this:
#RunWith(MockitoJUnitRunner.class) // This supports Eclemma Plugin. Powermock doesn't.
#PrepareForTest({/* StaticClasses for Powermock here */})
public class ClassTest {
// These two statements; the static block and #Rule make sure Powermock works along with Mockito!!
static {
PowerMockAgent.initializeIfNeeded();
}
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#Mock // To mock dependent class
private MockClass mock;
#InjectMocks //To Inject all mocks in this class
private ClassUnderTest classObject;
//Rest of the code here.
}
Dependencies needed:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-rule-agent</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency
Also you need to add this to the configurations under Coverage As -> Coverage Configurations -> Arguments.
Inside VM Arguments add -noverify and save.
for this to work with Jacoco use the following statement in your pom.xml .
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<argLine>${argLine} -noverify -javaagent:${settings.localRepository}/org/powermock/powermock-module-javaagent/1.6.2/powermock-module-javaagent-1.6.2.jar</argLine>
</configuration>
</plugin>