60

This simple unit test always passes and I can't figure out why.

@RunWith(JUnit4.class)
class SampleTest {
    @Test testSomething() {
        Uri uri = Uri.parse("myapp://home/payments");
        assertTrue(uri == null);
    }
}

What I have tried so far is using a "traditional" URI (http://example.com) but uri was also null.

3k-
  • 2,467
  • 2
  • 23
  • 24

7 Answers7

62

I resolve this problem with Robolectric.

these are my unit test config

build.gradle

dependencies {
...
testImplementation 'junit:junit:4.12'
testImplementation "org.robolectric:robolectric:3.4.2"
}

test class

@RunWith(RobolectricTestRunner.class)
public class TestClass {
    
    @Test
    public void testMethod() {
      Uri uri = Uri.parse("anyString")
      //then do what you want, just like normal coding
    }
}

kotlin

@RunWith(RobolectricTestRunner::class)
class TestClass {
   @Test
   fun testFunction() {
      val uri = Uri.parse("anyString")
      //then do what you want, just like normal coding
   }
}

it works for me, hope this can help you.

Vova
  • 956
  • 8
  • 22
Jeffery Ma
  • 3,051
  • 1
  • 23
  • 26
  • 9
    Why the -1 on this? In my mind, this is the actual correct answer because Robolectric gives you an actual implementation of Uri, not just a mock, along with implementations of everything else you'll need to unit test Android. – Bradford2000 Dec 21 '17 at 16:11
  • 4
    In recent version for `kotlin` you will have to use this `@RunWith(RobolectricTestRunner::class)` – Zohab Ali May 16 '21 at 19:31
30

Check if you have the following in your app's gradle file:

android {
    ...
    testOptions {
        unitTests.returnDefaultValues = true
    }

Uri is an Android class and as such cannot be used in local unit tests, without the code above you get the following:

java.lang.RuntimeException: Method parse in android.net.Uri not mocked. See http://g.co/androidstudio/not-mocked for details.

The code above suppresses this exception and instead provides dummy implementations returning default values (null in this case).

The other option is that you are using some framework in your tests that provides implementations of the methods in Android classes.

Marcin Jedynak
  • 3,697
  • 2
  • 20
  • 19
  • I stated in my OP that the test passes so there's no exception thrown. Moreover I not only need a non-null Uri object, I need a Uri object with specific properties (scheme, path, etc.) – 3k- Nov 17 '16 at 12:11
7

Uri is Android class therefore it needs to be mocked before using in tests.

See this answer for example: https://stackoverflow.com/a/34152256/5199320

Community
  • 1
  • 1
Rafal Zawadzki
  • 963
  • 6
  • 15
1

This was dumb...but I forgot to annotate my test class with: @RunWith(AndroidJUnit4::class)

Once I did that, everything worked as expected.

jacoballenwood
  • 2,787
  • 2
  • 24
  • 39
1

Use URL class instead of Uri.

import java.net.URL

fun getDomain(url: String): String {
    return URL(url).host
}

-------------

@Test
fun test() {
    Assert.assertEquals("www.ru", getDomain("https://www.ru"))
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224
0

Finally I just changed my code to accept URIs as String, so now it works both in production and test and omit the usage of Uri.parse(). Now where an URI is needed I just use uri.toString() instead of parsing a String.

3k-
  • 2,467
  • 2
  • 23
  • 24
  • 11
    I don't think that's a good idea. By using Uri you provide a higher level of type safely compared to strings. Strings can contain anything, with a Uri you know at least that it is a valid Uri. Your unit tests are supposed to increase your code quality, not decrease it. I would rather turn this test into a connected (Espresso) test. – Michael Nov 22 '17 at 23:44
  • 1
    Thanks, I understood that `Uri.parse` is Android-dependant method and removed it from code. – CoolMind Jun 08 '18 at 17:47
0

Below code solved my problem.

@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.P])
class TestClass
Enes Zor
  • 973
  • 8
  • 14