Binitkumarsingh / mockito

Automatically exported from code.google.com/p/mockito
0 stars 0 forks source link

Android support #308

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Hi, I'm a member of Android's Dalvik team. Lots of Android developers have been 
asking for Mockito support for Android, so we've written some code to make that 
possible.

The first part is a new library called 'dexmaker' that assumes the role of 
ASM+cglib on Android. Read more about dexmaker here:
http://code.google.com/p/dexmaker/

The second part is a clone to Mockito that integrates dexmaker. The clone is 
here:
  http://code.google.com/r/jessewilson-mockito/

Unfortunately it's slightly cumbersome to confirm that the tests pass on 
Android because there's no easy way to run JUnit 4 tests on Android. I hacked 
together the vogar test runner (http://code.google.com/p/vogar/) to run the 
tests; it would also be possible to run tests as a part of an Android 
application.

Original issue reported on code.google.com by jessewil...@google.com on 13 Jan 2012 at 3:38

GoogleCodeExporter commented 8 years ago
The process of building would be as follow:

1. compile sources to .class
2. convert .class to dex (dalvik byte code) and convert all libraries to dex 
(including mockito)
3a. package resources and dex files into APK (android package similar to a jar)
3b. include extra files from jar into APK - this is where it goes wrong

I believe Jesse, you use vogar as compile/test cycle which is obviously quite 
reducing for normal devs.

A good place to configure mockito would be within the InstrumentationTestRunner 
- both mockMacker and dexmaker cache dir:
http://developer.android.com/reference/android/test/InstrumentationTestRunner.ht
ml

I tried to figure out how to declare the mockMacker but could not find the 
easiest way to do so. Any suggestions? Currently I recompiled while using the 
root as search path for the config file

Original comment by charroch on 29 Feb 2012 at 12:13

GoogleCodeExporter commented 8 years ago
Yikes! I'll take a look at this.

In the worst case we can use "/services/org.mockito.plugins.MockMaker" instead 
of  "/META-INF/services/org.mockito.plugins.MockMaker".

Original comment by jessewil...@google.com on 29 Feb 2012 at 4:07

GoogleCodeExporter commented 8 years ago
I investigated the META-INF issue. You're right, it's going to be a problem. 
Nice catch, brice & charroch. I changed jessewilson-mockito's ClassPathLoader 
to look in services/ instead of META-INF/services, and fixed dexmaker to match.
  https://code.google.com/r/jessewilson-mockito/source/detail?r=d2225585e5c23e99d3641f286c3ce0467a53d3cd
  http://code.google.com/p/dexmaker/source/detail?r=60c59ca7eff486f674261b36d2d453f68bf0115d

I confirmed this all works by writing a regular Android test with the regular 
Android framework. This test exercises Mockito properly on-device.

Original comment by jessewil...@google.com on 3 Mar 2012 at 1:02

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
All credits must go to charroch for spotting this.

I'm a bit shocked by this behavior of 'ApkBuilder', and I find it a big catch 
for this issue.

META-INF is like a java internal Meta directory, and normally we shouldn't mess 
with it. Although it's used for the 'ServiceLoader' files, 'persistance.xml' 
with JPA, Spring can look inside, and so on.
I don't think there is a clear convention there.

As we are not using the real 'ServiceLoader' with '/META-INF/services', using 
'/services' with this name makes little sense in my opinion. Instead I propose 
to use our own 'mockito' folder(s), like '/mockito' or '/mockito/extensions'

Thoughts ?

(When will google code be upgraded with comment formatting, compared to git or 
bitbucket, stackoverflow, it lacks a lot in this area if not other :/ )

Original comment by brice.du...@gmail.com on 4 Mar 2012 at 5:24

GoogleCodeExporter commented 8 years ago
Sure. I'm not picky about which directory we use.

Original comment by limpbizkit on 4 Mar 2012 at 5:38

GoogleCodeExporter commented 8 years ago
I've discussed a bit with Szczepan, I think we will use the folder 
'mockito-extensions'.

I'll push changes in the default branch this afternoon.

Original comment by brice.du...@gmail.com on 5 Mar 2012 at 11:40

GoogleCodeExporter commented 8 years ago

Original comment by brice.du...@gmail.com on 5 Mar 2012 at 12:23

GoogleCodeExporter commented 8 years ago
OK, I pushed the ClassPathLoader modifications only, let me know if it work for 
ou with an AndroidMockMaker module.

Original comment by brice.du...@gmail.com on 5 Mar 2012 at 9:14

GoogleCodeExporter commented 8 years ago
Brice, awesome. I confirmed that the latest Mockito from hg works on Android 
when dexmaker.jar is on the classpath. I believe you can resolve this issue.

Original comment by jessewil...@google.com on 6 Mar 2012 at 3:08

GoogleCodeExporter commented 8 years ago
I'd like to rework a few things though, before closing the issue.
I'll update the issue thread when done.

Original comment by brice.du...@gmail.com on 6 Mar 2012 at 9:42

GoogleCodeExporter commented 8 years ago
Friendly ping! We're eager to adopt this, yet cautious about depending on 
unreleased features.

Original comment by jessewil...@google.com on 21 Mar 2012 at 12:58

GoogleCodeExporter commented 8 years ago
Hi Jesse,

I'm currently experimenting with Javassist, to see how things work together. So 
far so good!
The main issue is about the Javassist ProxyFactory which turned pretty limited 
as compared to the CGLIB's Enhancer, but that's another story. (We really need 
a CGLIB fork)

Just in case, I'd like to keep the @Incubating annotation until things have 
settled in the wild once released. I'll ask the team about that.

Anyway I think this is ok to make a release.

Thank you very much for pushing this one ;)

Cheers,
Brice

Original comment by brice.du...@gmail.com on 21 Mar 2012 at 9:51

GoogleCodeExporter commented 8 years ago
I cannot get Mockito working on Android. Tried like everything. Used the 1.9.1 
Snapshot of the master branch. Used latest build of jessewilson. Included 
dexmaker to my build path. But i'm always getting errors. 
Can somebody explain how to get Mockito working for Android?

Original comment by johannes...@gmail.com on 26 Mar 2012 at 2:15

GoogleCodeExporter commented 8 years ago
I've attached an example project. Run it like this:
  cd mockito-android-example-test
  ant debug install
  ant test
You should see two tests run, and one will fail. That's expected; I'm just 
demonstrating that verify() failures are handled.

Original comment by limpbizkit on 26 Mar 2012 at 2:54

Attachments:

GoogleCodeExporter commented 8 years ago
Hey! Thanks yes your example does work, but only on SDK level 15 (4.0.3). Am i 
doing something wrong?
Becouse you have your target SDK set on API 11 (3.0), but here emulator with 
API 11 (3.0) does not work.

If tried SDK 8 (2.2), 11 (3.0), 14 (4.0), 15 (4.0.3)

SDK 8 (2.2)
java.lang.ExceptionInInitializerError
at 
com.google.dexmaker.mockitoexample.MockitoExampleActivityTest.testFoo(MockitoExa
mpleActivityTest.java:29)
at java.lang.reflect.Method.invokeNative(Native Method)
at 
android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:204)
at 
android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:194)
at 
android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTes
tCase2.java:186)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at 
android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:52
0)
at 
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
Caused by: java.lang.ExceptionInInitializerError
at org.mockito.internal.MockitoCore.<init>(MockitoCore.java:37)
at org.mockito.Mockito.<clinit>(Mockito.java:767)
... 15 more
Caused by: java.lang.ExceptionInInitializerError
at org.mockito.internal.util.MockUtil.<clinit>(MockUtil.java:20)
... 17 more
Caused by: java.lang.NoSuchMethodError: java.lang.String.isEmpty
at 
org.mockito.internal.configuration.ClassPathLoader.loadImplementations(ClassPath
Loader.java:94)
at 
org.mockito.internal.configuration.ClassPathLoader.findPlatformMockMaker(ClassPa
thLoader.java:64)
at 
org.mockito.internal.configuration.ClassPathLoader.<clinit>(ClassPathLoader.java
:25)
... 18 more

SDK 14 (4.0) & SDK 11 (3.0)
java.lang.IllegalArgumentException: dexcache == null (and no default could be 
found; consider setting the 'dexmaker.dexcache' system property)
at com.google.dexmaker.DexMaker.generateAndLoad(DexMaker.java:359)
at com.google.dexmaker.stock.ProxyBuilder.buildProxyClass(ProxyBuilder.java:252)
at 
com.google.dexmaker.mockito.DexmakerMockMaker.createMock(DexmakerMockMaker.java:
51)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:41)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:41)
at org.mockito.Mockito.mock(Mockito.java:1061)
at org.mockito.Mockito.mock(Mockito.java:955)
at 
com.google.dexmaker.mockitoexample.MockitoExampleActivityTest.testFoo(MockitoExa
mpleActivityTest.java:29)
at java.lang.reflect.Method.invokeNative(Native Method)
at 
android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
at 
android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
at 
android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTes
tCase2.java:186)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at 
android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:52
5)
at 
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1547)

Original comment by johannes...@gmail.com on 26 Mar 2012 at 7:14

GoogleCodeExporter commented 8 years ago
String.isEmpty() wasn't available in Android until Gingerbread; so API level 9 
is our minimum requirement. It's not feasible to change all of Mockito to not 
use that or other Java 1.6+ APIs.

For the dexcache == null issue, I suspect we can fix that by improving our 
dexcache selection heuristic. This is where dexmaker generates temporary files 
on the filesystem. Here's the current implementation:
http://code.google.com/p/dexmaker/source/browse/src/main/java/com/google/dexmake
r/AppDataDirGuesser.java

Original comment by limpbizkit on 26 Mar 2012 at 7:32

GoogleCodeExporter commented 8 years ago
The dexcache directory can be any read/writable directory right?

The strange thing is that if i set it to the "/sdcard" directory i still get an 
error.
03-27 09:00:47.399: E/dalvikvm(568): Can't open dex cache 
'/data/dalvik-cache/sdcard@Generated-597192020.jar@classes.dex': No such file 
or directory
But the Generated-597192020.jar is created in the /sdcard directory

Original comment by johannes...@gmail.com on 27 Mar 2012 at 9:08

GoogleCodeExporter commented 8 years ago
I don't believe the SD card will work. It might be due to the way that 
partition is mounted (preventing memory mapping?) or perhaps its permissions 
(cannot be executed). It's also a lousy idea from a security perspective; since 
it's often world-writable you become an easy target for code injection attacks.

Original comment by limpbizkit on 27 Mar 2012 at 2:39

GoogleCodeExporter commented 8 years ago
> Caused by: java.lang.NoSuchMethodError: java.lang.String.isEmpty
> at 
org.mockito.internal.configuration.ClassPathLoader.loadImplementations(ClassPath
Loader.java:94)
> at 
org.mockito.internal.configuration.ClassPathLoader.findPlatformMockMaker(ClassPa
thLoader.java:64)
> at 
org.mockito.internal.configuration.ClassPathLoader.<clinit>(ClassPathLoader.java
:25)

That's unexpected, Mockito should work on a JDK 1.5. I'll fix it.

Original comment by brice.du...@gmail.com on 27 Mar 2012 at 3:31

GoogleCodeExporter commented 8 years ago
I'm getting an IllegalArgumentException when running verify() on methods with 
no args. Things are OK when there are args (from the 
InvocationHandlerAdapter.java source, looks like invoke(Object proxy, Method 
method, Object[] args) is getting a null for args). E.g.,

interface Whatever {
    void doStuff();
}

public void testWhatever() {
    final Whatever whateverMock = mock(Whatever.class);
    whateverMock.doStuff();
    verify(whateverMock).doStuff();
}

throws:

java.lang.IllegalArgumentException
    at com.google.dexmaker.mockito.InvocationHandlerAdapter.invoke(InvocationHandlerAdapter.java:49)
    at com.sanitas.wellaho.login.$Proxy26.doStuff(Unknown Source)
    at com.sanitas.wellaho.login.LoginTest.testWhatever(LoginTest.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at junit.framework.TestCase.runTest(TestCase.java:168)
    at junit.framework.TestCase.runBare(TestCase.java:134)
    at junit.framework.TestResult$1.protect(TestResult.java:110)
    at junit.framework.TestResult.runProtected(TestResult.java:128)
    at junit.framework.TestResult.run(TestResult.java:113)
    at junit.framework.TestCase.run(TestCase.java:124)
    at junit.framework.TestSuite.runTest(TestSuite.java:243)
    at junit.framework.TestSuite.run(TestSuite.java:238)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Original comment by allur...@gmail.com on 29 Mar 2012 at 7:56

GoogleCodeExporter commented 8 years ago
@allurefx, that's surprising. We're generating code to allocate an empty array; 
perhaps that isn't working as we want it to. I'll investigate. I've opened a 
dexmaker bug to track this here: 
http://code.google.com/p/dexmaker/issues/detail?id=4

Original comment by limpbizkit on 29 Mar 2012 at 10:57

GoogleCodeExporter commented 8 years ago
Thanks. I must add that I'm using mockito-all-1.9.1-SNAPSHOT.jar and 
dexmaker20120305.jar.

Original comment by allur...@gmail.com on 29 Mar 2012 at 11:07

GoogleCodeExporter commented 8 years ago
Just a little update, we are almost ready.

Though the Invocation type used in MockitoInvocationHandler raised question as 
wether it should be an interface instead.

If using an interface instead, then the bytecode internal interceptor could use 
a new Invocation factory to pass on the handler.

The API is marked as Incubating, which could mean we can introduce changes 
after the release, still I'd rather avoid it.

Maybe you have some feedback on this mattter ?

Cheers,

Original comment by brice.du...@gmail.com on 31 Mar 2012 at 10:39

GoogleCodeExporter commented 8 years ago
Hey guys,

We're getting closer to release the 1.9.5 that will officially support the 
MockMaker goodies. I'm going to shuffle some types a bit. MockMaker will still 
live under org.mockito.plugins However, the MockitoInvocationHandler and 
MockSettingsInfo have to move elsewhere. Depending what's your implementation 
of MockMaker, this might mean that you need reorganize imports and recompile. I 
hope it's not going to bother you that much :)

I've also done some work to properly make the Invocation type an interface and 
a public API (because it leaks via MockMaker). Depending on what kind of stuff 
you do in the MockMaker interface this might require recompilation and some 
fixes on your side. Sorry about that but we had to do it :/

I'll finish off this work today so feel free to give us feedback should 
anything be breaking the android support.

Thanks for patience :) The ETA for the 1.9.5 release candidate is next weekend.

Original comment by szcze...@gmail.com on 1 Apr 2012 at 3:31

GoogleCodeExporter commented 8 years ago
Fantastic! Fixing compilation on our side is no problem; we'll definitely 
appreciate the better API.

Original comment by limpbizkit on 1 Apr 2012 at 6:08

GoogleCodeExporter commented 8 years ago

Original comment by brice.du...@gmail.com on 3 Apr 2012 at 5:35

GoogleCodeExporter commented 8 years ago
@Jesse Do you have a wiki page for the Mockito Android plugin ?
We could eventually add a wiki page on Mockito. Though I feel it's more 
relevant on the plugin webiste, so we could link it from here.

Oh and by the way thanks for "you know what" ;)

Original comment by brice.du...@gmail.com on 3 Apr 2012 at 5:39

GoogleCodeExporter commented 8 years ago
I've created a stub wiki page here. I'll add details and troubleshooting as 
necessary.
http://code.google.com/p/dexmaker/wiki/Mockito

Original comment by jessewil...@google.com on 16 Apr 2012 at 3:31

GoogleCodeExporter commented 8 years ago
I'm getting a crash when I attempt to mock an object. I'm not sure if the crash 
is in dexmaker or mockito. I filed a ticket here. Is there something I'm doing 
incorrectly?  http://code.google.com/p/dexmaker/issues/detail?id=6

Original comment by MhaleK...@gmail.com on 11 May 2012 at 8:28

GoogleCodeExporter commented 8 years ago

Original comment by szcze...@gmail.com on 13 May 2012 at 3:37

GoogleCodeExporter commented 8 years ago
@MhaleKane Our MockMaker API was changed a bit, we wanted a proper API. So the 
dexmaker implementation is not yet up to date. You might wont to get an old 
Mockito snapshot from march.

@Jesse I think you can update the dexmaker implementation, as the big API 
refactorings are now in good shape.

(same answer on the dexmaker 
http://code.google.com/p/dexmaker/issues/detail?id=6)

Original comment by brice.du...@gmail.com on 14 May 2012 at 9:32

GoogleCodeExporter commented 8 years ago
Great  job  guys.  I  tried lots  of  libraries  for  unit  testing  on  
android  and  am  happy  that  I  found  dexmaker +  mockito(unofficial build  
off  sources)  doing  the  job. When  can we  get a official  build  of  
mockito  with  android  support?

Original comment by vipina...@gmail.com on 22 May 2012 at 1:47

GoogleCodeExporter commented 8 years ago

Original comment by szcze...@gmail.com on 3 Jun 2012 at 2:06

GoogleCodeExporter commented 8 years ago

Original comment by brice.du...@gmail.com on 3 Sep 2012 at 10:00

GoogleCodeExporter commented 8 years ago

Original comment by brice.du...@gmail.com on 19 Dec 2012 at 10:59