robolectric / robolectric

Android Unit Testing Framework
http://robolectric.org
Other
5.81k stars 1.36k forks source link

Can't access "new AccessibilityEvent()" with Robolectric 4.12 #9045

Closed utzcoz closed 3 weeks ago

utzcoz commented 4 weeks ago

Description

Chromium's Robolectric tests use new AccessibilityEvent() to obtain an AccessibilityEvent instance, and it works with Robolectric 4.11.x. But when I tried to bump Robolectric to 4.12.1 for it, it failed with the reason it can't access new AccessiblityEvent().

Steps to Reproduce

See https://chromium-review.googlesource.com/c/chromium/src/+/5419446.

I will add extra tests in Robolectric very soon to test its behavior.

Robolectric & Android Version

Robolectric 4.12.1.

Link to a public git repo demonstrating the problem:

Robolectric itself.

hoisie commented 4 weeks ago

Can you print the whole stack trace?

utzcoz commented 4 weeks ago
C 11:47:12.724  168.812s Main  39| D/LifecycleMonitor: Lifecycle status change: androidx.appcompat.app.AppCompatActivity@1ffec5c7 in: PRE_ON_CREATE
C 11:47:12.724  168.812s Main  39| D/LifecycleMonitor: Lifecycle status change: androidx.appcompat.app.AppCompatActivity@1ffec5c7 in: CREATED
C 11:47:12.724  168.812s Main  39| D/LifecycleMonitor: Lifecycle status change: androidx.appcompat.app.AppCompatActivity@1ffec5c7 in: STARTED
C 11:47:12.725  168.813s Main  39| D/LifecycleMonitor: Lifecycle status change: androidx.appcompat.app.AppCompatActivity@1ffec5c7 in: RESUMED
C 11:47:12.725  168.813s Main  39| E/ResourcesCompat: Failed to find font-family tag
C 11:47:12.725  168.813s Main  39| java.lang.IllegalAccessError: class org.chromium.chrome.browser.readaloud.player.expanded.MenuUnitTest tried to access private method 'void android.view.accessibility.AccessibilityEvent.<init>()' (org.chromium.chrome.browser.readaloud.player.expanded.MenuUnitTest and android.view.accessibility.AccessibilityEvent are in unnamed module of loader org.robolectric.internal.AndroidSandbox$SdkSandboxClassLoader @55141def)
C 11:47:12.725  168.813s Main  39|  at org.chromium.chrome.browser.readaloud.player.expanded.MenuUnitTest.testMenuItemLayoutInflated(MenuUnitTest.java:195)
C 11:47:12.725  168.813s Main  39|  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
C 11:47:12.725  168.813s Main  39|  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
C 11:47:12.725  168.813s Main  39|  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
C 11:47:12.725  168.813s Main  39|  at java.base/java.lang.reflect.Method.invoke(Method.java:568)
C 11:47:12.725  168.813s Main  39|  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
C 11:47:12.725  168.813s Main  39|  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
C 11:47:12.725  168.813s Main  39|  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:61)
C 11:47:12.725  168.813s Main  39|  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
C 11:47:12.725  168.813s Main  39|  at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
C 11:47:12.725  168.813s Main  39|  at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
C 11:47:12.725  168.813s Main  39|  at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:489)
C 11:47:12.725  168.813s Main  39|  at org.chromium.base.test.BaseRobolectricTestRunner$HelperTestRunner$1.evaluate(BaseRobolectricTestRunner.java:43)
C 11:47:12.725  168.813s Main  39|  at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290)
C 11:47:12.725  168.813s Main  39|  at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:104)
C 11:47:12.725  168.813s Main  39|  at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
C 11:47:12.725  168.813s Main  39|  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
C 11:47:12.725  168.813s Main  39|  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
C 11:47:12.725  168.813s Main  39|  at java.base/java.lang.Thread.run(Thread.java:840)
C 11:47:12.725  168.813s Main  39|  Suppressed: org.robolectric.android.internal.AndroidTestEnvironment$UnExecutedRunnablesException: Main looper has queued unexecuted runnables. This might be the cause of the test failure. You might need a shadowOf(Looper.getMainLooper()).idle() call.

@hoisie This is the stack trace of failures.

utzcoz commented 4 weeks ago

@hoisie I think it might related to these APIs were added from SDK 30: https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent#AccessibilityEvent(). I am drafting a PR to add necessary tests for AccessibilityEvent constructors.

utzcoz commented 4 weeks ago

From https://github.com/robolectric/robolectric/pull/9046, developers can access new AccessibilityEvent() and new AccessibilityNodeInfo() if they set the minSdk to 30.

hoisie commented 4 weeks ago

@utzcoz Ah I think this is the commit that probably caused the error:

c47fa04d3ac9699ff820e2dfc663ff0c8a7675c1

TLDR is that Robolectric was making all constructors public, so the update was to be more consistent with real Android.

hoisie commented 4 weeks ago

For instance, the public AccessibilityNodeInfo () constructor was added in SDK 30. Previously, it was a private constructor. However, using new AccessibilityNodeInfo() used to work in all SDK levels in Robolectric (until that was fixed). We don't want to mislead people into thinking that is possible with older SDK levels.

hoisie commented 4 weeks ago

To get around the issue:

1) Set the minSdk to 30 (or whatever it is)

2) Use ReflectionHelpers.callConstructor

You just can't use new AccessibilityEvent() on older SDks.

utzcoz commented 4 weeks ago

c47fa04d3ac9699ff820e2dfc663ff0c8a7675c1

Yeah. It also breaks the Mockito's @Spy as it also requires empty constructor of the class.

utzcoz commented 3 weeks ago

@hoisie Thanks for your explanation, and I think the change is reasonable, and let's close the issue.