TestParameterInjector icon indicating copy to clipboard operation
TestParameterInjector copied to clipboard

Can't use more than one `TestParameter` annotation with Android Instrumentation tests.

Open ultraon opened this issue 4 years ago • 8 comments

When I use only one property with TestParameter annotation tests works well. As soon as I add a 2nd property with TestParameter annotation then all tests fail.

After some investigation I've found that androidx.test.runner.AndroidJUnitRunner.runnerArgs.tests contains incorrect list of test classes:

  • my.test.MyTestClass#testCheckSmth[boolParam1=false
  • boolParam2=false]

And as soon as TestLoader.doCreateRunner() tries to create test class instance from string boolParam2=false] using reflection it fails later.

It is possible that input parameters incorrectly parsed from test args bundle splitting my.test.MyTestClass#testCheckSmth[boolParam1=false,boolParam2=false] by coma.

Test class sample:

// This is instrumentation test, should run on device or emulator
@RunWith(TestParameterInjector::class)
class MyTestClass {

	@TestParameter
	var boolParam1 = false

	@TestParameter
	var boolParam2 = false

	@Test
	fun testCheckSmth() {
	  // test body...
	}
}

When I use the same sample with standard JUnit tests it works well.

Test output:

Starting 4 tests on Android_TV_720p_API_Q(AVD) - Q

boolParam2=false] > [Android_TV_720p_API_Q(AVD) - Q] FAILED 
        java.lang.ClassNotFoundException: Invalid name: boolParam2=false]
        at java.lang.Class.classForName(Native Method)

boolParam2=true] > [Android_TV_720p_API_Q(AVD) - Q] FAILED 
        java.lang.ClassNotFoundException: Invalid name: boolParam2=true]
        at java.lang.Class.classForName(Native Method)

boolParam2=false] > [Android_TV_720p_API_Q(AVD) - Q] FAILED 
        java.lang.ClassNotFoundException: Invalid name: boolParam2=false]
        at java.lang.Class.classForName(Native Method)

boolParam2=true] > [Android_TV_720p_API_Q(AVD) - Q] FAILED 
        java.lang.ClassNotFoundException: Invalid name: boolParam2=true]
        at java.lang.Class.classForName(Native Method)

> Task :app:connectedDebugAndroidTest FAILED

ultraon avatar Jun 08 '21 20:06 ultraon

Just in case, I tried with https://github.com/square/burst - have the same issue.

ultraon avatar Jun 08 '21 20:06 ultraon

Looks like this library doesn't work well with AndroidJUnitRunner.

Can you give an example of how I can reproduce this locally? How do I combine AndroidJUnitRunner and TestParameterInjector?

nymanjens avatar Jun 09 '21 07:06 nymanjens

Spaces are not supported: https://github.com/android/android-test/issues/956 might be the same issue with commas as that's the separator for listing explicit executions.

TWiStErRob avatar Nov 06 '21 20:11 TWiStErRob

Right, so this could be fixed by filtering spaces and commas from the test name for Android tests.

I guess TestParameterInjector could look at the classpath and see if AndroidJUnitRunner is loaded in there.

nymanjens avatar Nov 08 '21 08:11 nymanjens

Careful, Robolectric might also have it on classpath. See https://robolectric.org/blog/2021/10/06/sharedTest/

TWiStErRob avatar Nov 08 '21 09:11 TWiStErRob

Hmm, so replacing spaces/commas by underscores is really easy, but I wouldn't want to do this for more use cases than necessary. As a non-expert on Android, can anyone recommend a good way of distinguishing this AndroidJUnitRunner-like use case from others that are working fine (if they exist)?

nymanjens avatar Nov 23 '21 12:11 nymanjens

I would recommend checking Espresso source code to see how they detect if the OS is Android. I'm sure okhttp/okio also has one too.

TWiStErRob avatar Nov 23 '21 13:11 TWiStErRob

Just tried this today with a fairly up-to-date Android project and tools, and this seems to work fine now? At least, it was running with my usage with more than one TestParameter.

alexvanyo avatar Aug 19 '22 01:08 alexvanyo