Android:PowerMock work in "test" folder but not work in "androidTest" folder - powermock

I want to test 2 static methods in Android app. So I use PowerMock for this.
I write 2 tests. One unit test and one instrumented unit test.
My android build.gradle:
dependencies {
androidTestCompile "org.mockito:mockito-android:2.7.21"
androidTestCompile "org.powermock:powermock-api-mockito:1.6.6"
androidTestCompile 'org.powermock:powermock-module-junit4:1.6.6'
testCompile 'junit:junit:4.12'
testCompile 'org.powermock:powermock-api-mockito:1.6.6'
testCompile 'org.powermock:powermock-module-junit4:1.6.6'
}
Unit test is in folder: app/src/test/java/com/mycompany/StringUtilTest.java
Here code:
#RunWith(PowerMockRunner.class)
#PrepareForTest(StringUtil.class)
public class StringUtilTest {
#Test
public void isCorrectEmailStub() {
// mock all the static methods in a class called "StringUtil"
mockStatic(StringUtil.class);
String INCORRECT_EMAIL_TO_CHECK = "incorrect_email_some.com";
when(StringUtil.isCorrectEmail(INCORRECT_EMAIL_TO_CHECK)).thenReturn(true);
assertThat(StringUtil.isCorrectEmail(INCORRECT_EMAIL_TO_CHECK), is(true));
}
}
And it work fine. OK.
Instrumented unit test is in folder: app/src/androidTest/java/com/mycompany/StringUtilInstrumentedTest.java
Here code:
#RunWith(PowerMockRunner.class)
#PrepareForTest(StringUtil.class)
public class StringUtilInstrumentedTest {
private static String TAG;
private Context context;
#Before
public void init() {
TAG = StringUtilInstrumentedTest.class.getName();
context = InstrumentationRegistry.getTargetContext();
}
#Test
public void decliningAge() {
// mock all the static methods in a class called "StringUtil"
mockStatic(StringUtil.class);
// use Mockito to set up your expectation
String expected = "first";
when(StringUtil.decliningAge(context, 1)).thenReturn(expected);
assertThat(StringUtil.decliningAge(context, 1), is(expected));
}
}
But when I run this test I get error:
java.lang.ClassNotFoundException: com.mycompany.StringUtilInstrumentedTest
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:324)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)
Caused by: java.lang.IllegalStateException: Failed to transform class with name com.mycompany.StringUtilInstrumentedTest.Reason: com.mycompany.StringUtilInstrumentedTest
at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:284)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:192)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass1(DeferSupportingClassLoader.java:77)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
Caused by: javassist.NotFoundException: com.mycompany.StringUtilInstrumentedTest
at javassist.ClassPool.get(ClassPool.java:452)
at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:262)

Related

How to load values from custom properties file for junit testing using Mockito?

I have written this test class to check a service. This is in folder test/java/example/demp/Test.java
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource("classpath:conn.properties")
public class DisplayServiceTest {
#Value("${id}")
private String value;
#Mock
private DisplayRepository DisplayReps;
#InjectMocks
private DisplayService DisplayService;
#Test
public void whenFindAll_thenReturnProductList() {
Menu m = new Menu()
m.setId(value); //when I print value its showing 0
List<Display> expectedDisplay = Arrays.asList(m);
doReturn(expectedDisplay).when(DisplayReps).findAll();
List<Display> actualDisplay = DisplayService.findAll();
assertThat(actualDisplay).isEqualTo(expectedDisplay);
}
My properties file
This is in folder test/resources/conn.properties
id=2
What is the right way to set properties from custom properties file? Cause its not loading values ?
Mockito is a mocking framework, so in general you can't load properties file with Mockito.
Now you've used #TestPropertySource which is a part of Spring Testing and it indeed allows loading properties file (that have nothing to do with mockito though). However using it requires running with SpringRunner and in general its good for integration tests, not for unit tests (Spring Runner among primarily loads Spring's application context).
So if you don't want to use spring here, you should do it "manually". There are many different ways to load Properties file from class path (with getClass().getResourceAsStream() to get the input stream pointing on the resource file and the read it into Properties by using Properties#load(InputStream) for example.
You can also use other thirdparties (not mockito), like apache commons io to read the stream with IOUtils class
If you want to integrate with JUnit 4.x you can even create a rule, described here
#TestPropertySource is a spring annotation, so you need to use the SpringRunner.
You can initialize Mockito using MockitoAnnotations.initMocks(this);, check the example below.
#RunWith(SpringRunner.class)
#TestPropertySource("classpath:conn.properties")
public class DisplayServiceTest {
#Value("${id}")
private String value;
// ...
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
// ...
}
You could use just Mockito and JUnit 4. At the #Before method, call MockitoAnnotations.initMocks and load the properties file:
public class DisplayServiceTest {
private String value;
#Mock
private DisplayRepository displayReps;
#InjectMocks
private DisplayService displayService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Properties prop = loadPropertiesFromFile("conn.properties");
this.value = prop.getProperty("id");
}
private Properties loadPropertiesFromFile(String fileName) {
Properties prop = new Properties();
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream stream = loader.getResourceAsStream(fileName);
prop.load(stream);
stream.close();
} catch (Exception e) {
String msg = String.format("Failed to load file '%s' - %s - %s", fileName, e.getClass().getName(),
e.getMessage());
Assert.fail(msg);
}
return prop;
}
#Test
public void whenFindAll_thenReturnProductList() {
System.out.println("value: " + this.value);
Menu m = new Menu();
m.setId(this.value); // when I print value its showing 0
List<Display> expectedDisplay = Arrays.asList(m);
Mockito.doReturn(expectedDisplay).when(this.displayReps).findAll();
List<Display> actualDisplay = this.displayService.findAll();
Assert.assertEquals(expectedDisplay, actualDisplay);
}
}

JUnit testing of Ratpack server with Guice injection

I am trying to write a JUnit test with service dependencies being injected.
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
#Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(appRegistry -> {
// Allow modifying Injector in tests
return appRegistry.join(Guice.registry(injector));
}));
}
};
private Injector injector = com.google.inject.Guice.createInjector(new Module());
#Before
public void setup () {
injector.injectMembers(this);
}
#After
public void tearDown() {
aut.close();
}
and then using injected services in my test classes:
#Inject
private UserService userService;
This was working fine until I started adding persistence to my app with HikariModule. Now Guice registry creation is a bit more complex:
.join(Guice.registry(b -> b
.module(HikariModule.class, hikariConfig -> {
final String dbUrl = System.getenv("JDBC_DATABASE_URL");
hikariConfig.setJdbcUrl(dbUrl);
})
.module(Module.class)
.bind(DbMigrator.class)
).apply(r))
Because my registry now consists of multiple modules if I have a service that depends on DataSource class coming from HikariModule guice injection fails in tests.
My goal is to allow writing tests in the following fashion:
#Inject // <- not required can be done in #Before method
private UserService userService; // <- Inject it somehow from Application under test
#Test
public void testUser() {
final Result<User, String> userResult = userService.create(new User.Registration());
final ReceivedResponse res = aut.getHttpClient().get("/users/" + user.userId);
assertEquals(200, res.getStatusCode());
}
What is the right approach of injecting service dependencies in tests? I would very much prefer reusing guice modules from MainClassApplicationUnderTest rather than creating my own and overriding them.
After quite some time battling with this issue and help from Ratpack slack I managed to pull this off.
First of all we need to capture our application registry in the local variable.
private Registry appRegistry;
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
#Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(r -> {
appRegistry = r;
return Registry.empty();
}));
}
};
It turns out there is a nifty method that starts the application. So when injecting the class we will know that Registry will not be null and we can inject classes.
protected <T> T inject(final Class<T> classOf) {
aut.getAddress();
return appRegistry.get(classOf);
}
Then in test classes we can simply inject any class that is present in the registry.
final UserService userService = inject(UserService.class);
// OR
final DataSource dataSource = inject(DataSource.class);

Can any one help me in mocking a static method which returns an object, and this static method is present in a final class

I need help for below thing,
I have to write a Junit using PowerMock/Mockito for a method which makes a call to a static method of a final class present in an external jar.
The method for which i need to write the JUnit test is:
public class SomeClass {
private PrivateKey privateKeyFromPkcs8(String privateKeyPem) throws IOException {
Reader reader = new StringReader(privateKeyPem);
Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY");
if (section == null) {
throw new IOException("Invalid PKCS8 data.");
}
byte[] bytes = section.getBase64DecodedBytes();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
try {
KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory();
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (NoSuchAlgorithmException exception) {
} catch (InvalidKeySpecException exception) {
}
throw new IOException("Unexpected exception reading PKCS data");
}
}
In the above code PemReader is a final class and readFirstSectionAndClose(reader, "PRIVATE KEY") is a static method in PemReader.
I have tried writing the test shown below but Section object(section) is showing as null while debugging. Perhaps the actual code (PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY")) is getting called instead of the mock.
#RunWith(PowerMockRunner.class)
#PrepareForTest({SomeClass.class,PemReader.class})
public class SomeClassTest {
#InjectMocks
SomeClass mockSomeClass;
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testPrivateKeyFromPkcs8() throws Exception {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
assertNotNull(mockSomeClass.privateKeyFromPkcs8(dummyPrivateKey));
}
}
Please help me in writing a Junit using powermockito/mockito
You have to prepare the final, static class.
Here's an example using the PowerMock annotations for JUnit:
#RunWith(PowerMockRunner.class)
#PrepareForTest({PemReader.class})
public class PemReaderTest {
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testMockingStatic() {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
Assert.assertEquals(mockSection, PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY"));
}
}
For completeness, here's the definition of PemReader:
public final class PemReader {
public static Section readFirstSectionAndClose(Reader reader, String key) {
return null;
}
}
The above test passes with the following versions:
JUnit: 4.12
Mockito: 2.7.19
PowerMock: 1.7.0
Update 1: based on your updated question. Your test case will pass (or at least the invocation on PemReader.readFirstSectionAndClose will return something) if you just make this change:
Mockito.when(PemReader.readFirstSectionAndClose(
Mockito.any(Reader.class),
Mockito.eq("PRIVATE KEY"))
).thenReturn(mockSection);
The version of this instruction in your current test case relies on equality matching between the StringReader which your code passes into readFirstSectionAndClose and the mocked Reader which your test case supplies. These are not 'equal' hence the mocked invocation's expectations are not met and your mockSection is not returned.
A few, unrelated, notes:
There is no need to include SomeClass.class in #PrepareForTest, you only need to include the classes which you want to mock in that annotation, since SomeClass is the class you are trying to test there is no mocking required for that class.
Using #InjectMocks to instance SomeClass is a bit odd, since SomeClass has no (mockito provided) mocks to inject into it :) you can replace this declaration with SomeClass someClass = new SomeClass();
In the code you supplied SomeClass.privateKeyFromPkcs8 has private scope so it cannot be tested (or called in any way) from SomeClassTest.

Robolectric java.lang.IllegalArgumentException: class com.android.app.R contains final fields

I am testing a legacy app with resources distributed across 3 packages.
So I extended RobolectricTestRunner and modified resource path as below.
public class DialerRobolectricTestRunner extends RobolectricTestRunner {
#Override
protected AndroidManifest getAppManifest(Config config) {
return new AndroidManifest(Fs.fileFromPath(manifestPath),
Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)) {
#Override
public List<ResourcePath> getIncludedResourcePaths() {
List<ResourcePath> paths = super.getIncludedResourcePaths();
paths.add(new ResourcePath(getRClass(),Fs.fileFromPath("../pkg1/res/"), getAssetsDirectory()));
paths.add(new ResourcePath(getRClass(), Fs.fileFromPath("../pkg2/res/"), getAssetsDirectory()));
paths.add(new ResourcePath(getRClass(), Fs.fileFromPath("../pkg2/res/"), getAssetsDirectory()));
return paths;
}
}
}
I see below exception while testing android app with Robolectric
java.lang.IllegalArgumentException: class com.android.app.R contains final fields, these will be inlined by the compiler and cannot be remapped.
Robolectric : 3.3.2,
sdk : 23

getAnnotation(Class<T>) always returns null when I'm using EasyMock/PowerMock to mock java.lang.reflect.Method

The tested method has the following code:
SuppressWarnings suppressWarnings = method.getAnnotation(SuppressWarnings.class);
In my test method.I mocked java.lang.reflect.Method:
Method method= PowerMock.createMock(Method.class);
SuppressWarnings sw = EasyMock.createMock(SuppressWarnings.class);
EasyMock.expect(method.getAnnotation(SuppressWarnings.class)).andReturn(sw);
In the tested method,
method.getAnnotation(SuppressWarnings.class); always returns null.
I don't know why.Could anyone help me?
//code:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Anonymous {
}
public class AnnotationClass {
public Anonymous fun(Method m){
Anonymous anonymous = m.getAnnotation(Anonymous.class);
return anonymous;
}
}
// test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Method.class)
public class AnnotationClassTest {
#Test
public void test() throws NoSuchMethodException, SecurityException {
AnnotationClass testClass = new AnnotationClass();
final Method mockMethod = PowerMock.createMock(Method.class);
final Anonymous mockAnot = EasyMock.createMock(Anonymous.class);
EasyMock.expect(mockMethod.getAnnotation(Anonymous.class)).andReturn(mockAnot);
PowerMock.replay(mockMethod);
final Anonymous act = testClass.fun(mockMethod);
Assert.assertEquals(mockAnot, act);
PowerMock.verify(mockMethod);
}
}
error:
java.lang.AssertionError: expected:<EasyMock for interface
com.unittest.easymock.start.Anonymous> but was:<null>
SuppressWarnings has #Retention(value=SOURCE) which means that it is not available at runtime:
public static final RetentionPolicy SOURCE: Annotations are to be discarded by the compiler.
However, if you would try your code with a different annotation that is available at runtime, method.getAnnotation(MyAnnotation.class) would still return null. That is, because by default the mocked Method will return null for method calls.
I think your problem is in the configuration of the mock, when I run your code (using an annotation that is available at runtime) I get the following exception:
Exception in thread "main" java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:466)
at org.easymock.EasyMock.expect(EasyMock.java:444)
at MockStuff.main(MockStuff.java:54)
This page has some explanations about how to mock a final class (such as Method).
Your code gives the exact same result for me. I was able to get it working using the following code:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Method.class)
public class AnnotationClassTest {
#Test
public void test() throws NoSuchMethodException, SecurityException {
final Method mockMethod = PowerMock.createMock(Method.class);
final Anot mockAnot = EasyMock.createMock(Anot.class);
EasyMock.expect(mockMethod.getAnnotation(Anot.class)).andReturn(mockAnot);
PowerMock.replay(mockMethod);
final Anot methodReturn = mockMethod.getAnnotation(Anot.class);
Assert.assertEquals(mockAnot, methodReturn);
}
}
#Retention(RetentionPolicy.RUNTIME)
#interface Anot {}
Note that this code is self contained, I defined the Anot interface since you didn't give the definition of Anonymous.