📱

Android Test Junit4 入門

2024/06/11に公開

2024年6月現在いまだに現役なJunit4さん

使い方がわからなかったのでメモ

基本の使い方

Androidフレームワークを使用しない単体テスト

class Junit4Test {
    @Before
    fun setUp() {
        println("setup")
    }

    @After
    fun tearDown() {
        println("tearDown")
    }

    @Test
    fun do1plus1Return_2() {
        val actual = 1 + 1
        assertEquals(2, actual)
    }

    @Test
    fun assertTrue() {
        val actual = true
        assertTrue(actual)
    }

    @Test
    fun assertFalse() {
        val actual = false
        assertFalse(actual)
    }

    @Test(expected = IndexOutOfBoundsException::class)
    fun throwException() {
        val list = emptyList<Int>()
        list[0]
    }

    @Ignore("skip this test")
    @Test
    fun skip() {
        println("skip")
    }

    @Test
    fun stringAssert() {
        val actual = "Hello"
        assertThat(actual, equalTo("Hello"))
        assertThat(actual, not(equalTo("World")))
        assertThat(actual, startsWith("H"))
        assertThat(actual, endsWith("o"))
        assertThat(actual, containsString("el"))
    }
}

Androidフレームワークを利用するインストゥルメントテスト

AndroidXのテストフレームワークがあるのでRobolectricは使用しなくてもいいかも

@Config(minSdk = 24, maxSdk = 34)
@RunWith(AndroidJUnit4::class)
class JetpackTest {
    @Test
    fun gettingContextTest() {
        val context = InstrumentationRegistry.getInstrumentation().targetContext
        val appName = context.getString(R.string.app_name)
        assertTrue(appName == "TestPractice")
    }
}

複数のテストクラスで事前処理を共通して使用したい時

全てのテストクラスの@Beforeで同じ処理を書くのは冗長的なのでEnclosedというものを使用する

テストクラスを作ってその中に抽象クラスを入れる

@Config(minSdk = 24, maxSdk = 34)
@RunWith(Enclosed::class)
class StringUtilityTest {
    abstract class StringTest {
        lateinit var test: String

        @Before
        fun setUpParent() {
            test = "Hello"
        }
    }
}

@Config(minSdk = 24, maxSdk = 34)
@RunWith(AndroidJUnit4::class)
class JetpackTest: StringUtilityTest.StringTest() {
   
    @Test
    fun gettingString() {
        assertEquals("Hello", test)
    }
}

Enclosedを利用したRoomのテスト

@Config(minSdk = 24, maxSdk = 34)
@RunWith(Enclosed::class)
class EnclosedTest {
    abstract class DBTest {
        lateinit var repositoryLocalDataSource: RepositoryLocalDataSource

        @Before
        fun setUpParent() {
            val context = InstrumentationRegistry.getInstrumentation().targetContext
            val db = Room
                .databaseBuilder(context, AppDatabase::class.java, "DB")
                .allowMainThreadQueries()
                .build()
            repositoryLocalDataSource = RepositoryLocalDataSource(db)
        }
    }
}

@Config(minSdk = 24, maxSdk = 34)
@RunWith(AndroidJUnit4::class)
class BlankRecord : EnclosedTest.DBTest() {
    @Test
    fun insertAll_successfully_persist_record() {
        repositoryLocalDataSource.insertAll(
            Repository(1, "hello", "hello", "shiroyama"),
        )
        val shiroyamaOwners = repositoryLocalDataSource.findByOwner("shiroyama")
        assertEquals(1, shiroyamaOwners.size)
    }
}

@Config(minSdk = 24, maxSdk = 34)
@RunWith(AndroidJUnit4::class)
class RecordPrepared : EnclosedTest.DBTest() {

    @Before
    fun setUp() {
        repositoryLocalDataSource.insertAll(
            Repository(1, "hello", "hello", "shiroyama"),
            Repository(2, "world", "world", "shiroyama"),
            Repository(3, "world", "world", "yamazaki")
        )
    }

    @Test
    fun findByOwner_givenShiroyama_returnsSizeCount2() {
        val shiroyamaOwners = repositoryLocalDataSource.findByOwner("shiroyama")
        assertEquals(2, shiroyamaOwners.size)
    }

    @Test
    fun findByOwner_givenYamazaki_returnsSizeCount1() {
        val list = repositoryLocalDataSource.findByOwner("yamazaki")
        assertEquals(1, list.size)
    }
}

Discussion