๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Unit Testing - Retrofit

interfacer_han 2024. 7. 8. 12:56

#1 ์ด์ „ ๊ธ€

#1-1 Unit Testing ๊ฐœ์š”

 

[Android] Unit Testing - ๊ฐœ์š”์™€ ํ™˜๊ฒฝ ์„ค์ •

#1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ#1-1 ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜๋จผ์ €, ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ๊ฐœ์š”๋ฅผ ์ฝ์œผ๋ฉด ์ข‹๋‹ค. ํ•ด๋‹น ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ๋ณต์‚ฌํ•ด์˜จ ์œ„์˜ ๊ทธ๋ฆผ

kenel.tistory.com

์œ„ ๋งํฌ์— ์žˆ๋Š” ์ด์ „ ๊ฒŒ์‹œ๊ธ€์— ์ด์–ด์„œ, ์‹ค์ œ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด Retrofit์˜ Unit Testing์„ ์ˆ˜ํ–‰ํ•ด๋ณธ๋‹ค. ๋ณธ ๊ฒŒ์‹œ๊ธ€์„ ์ฝ๊ธฐ ์ „์— [Android] Unit Testing - ๊ธฐ์ดˆ๋ฅผ ๋ณด๊ณ  ์˜ค๋ฉด ์ดํ•ด์— ๋„์›€์ด ๋œ๋‹ค.
 

#1-2 ํ™˜๊ฒฝ ์„ค์ • (build.gradle ๋“ฑ)

์ด์ „ ๊ฒŒ์‹œ๊ธ€์˜ #3์„ ํ† ๋Œ€๋กœ ๋ณธ ๊ฒŒ์‹œ๊ธ€์— ๋‚˜์˜ค๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์˜ Gradle, AGP, JDK์˜ ๋ฒ„์ „ ์„ค์ • ๋ฐ build.gradle ์„ค์ •์„ ์ง„ํ–‰ํ•œ๋‹ค. ์ด์ „ ๊ฒŒ์‹œ๊ธ€์˜ build.gradle๊ณผ ๋‹ฌ๋ฆฌ, ๋ณธ ๊ฒŒ์‹œ๊ธ€์—์„œ๋Š” Unit Testing์— ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” build.gradle์˜ plugins { ... }, buildFeatures { ... }, dependencies { ... }์˜ ์ผ๋ถ€ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ–ˆ๋‹ค. ์ด๋Š”  ์ฝ”๋“œ ๋‹ค์ด์–ดํŠธ๋ฅผ ์œ„ํ•œ ๊ฐœ์ธ์ ์ธ ์ œ๊ฑฐ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๊ธ€์€ ๋ณด๋Š” ์‚ฌ๋žŒ์€ ์ œ๊ฑฐ ์—†์ด ๊ทธ๋ƒฅ ๋ณต์‚ฌ ๋ฐ ๋ถ™์—ฌ๋„ฃ๊ธฐํ•ด๋„ ๋œ๋‹ค.
 

#2 Unit Testing์„ ์ ์šฉํ•  ์ƒ˜ํ”Œ ์•ฑ

#2-1 ์›๋ณธ ์•ฑ

 

[Android] Retrofit - ๊ธฐ์ดˆ

#1 ์ด์ „ ๊ธ€ [Android] Retrofit - ๋ฐฐ๊ฒฝ๊ณผ ๊ตฌ์กฐ#1 Restrofit์˜ ๋ฐฐ๊ฒฝ#1-1 REST API REST API (REpresentational State Transfer Application Programming Interface)#1 ๋ฌด์—‡(What)์— ๋Œ€ํ•œ API์ธ๊ฐ€?#1-1 ๊ฐœ์š”REST(REpresentational State Transfer) ๋˜๋Š”

kenel.tistory.com

์ด ๊ฒŒ์‹œ๊ธ€์˜ ์™„์„ฑ๋œ ์•ฑ์„ ๊ฐ€์ ธ์™€์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ํ•ด๋‹น ์•ฑ์„ ๊ฐ€์ ธ์™€์„œ #1-2์— ๋งž๊ฒŒ ํ™˜๊ฒฝ ์„ค์ •์„ ์ˆ˜์ •ํ•œ๋‹ค.
 

#2-2 MainActivity ์ผ๋ถ€ ์ˆ˜์ •ํ•ด์„œ album_reponse.json ์–ป๊ธฐ

...

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...

        val responseLiveData: LiveData<Response<Albums>> = liveData {
            val response1 = retrofitService.getAlbums()
            val response2 = retrofitService.getSortedAlbums(7)

            logResponseBody(response1)

            emit(response1)
        }

        responseLiveData.observe(this, Observer {
            ...
        })
    }

    private fun logResponseBody(response: Response<Albums>) {
        val responseBody = response.body()
        val gson = GsonBuilder().setPrettyPrinting().create()
        val jsonFormatted : String = gson.toJson(responseBody)

        Log.i("interfacer_han", "$jsonFormatted")
    }

    private fun appendListOnTextView(textView: TextView, list: Response<Albums>) {
        ...
    }
}

ํ•ด๋‹น ์•ฑ์˜ ์†Œ์Šค ์ฝ”๋“œ ์ค‘ MainActivity์˜ LiveDataBuilder๋ฅผ ์ผ๋ถ€ ์ˆ˜์ •ํ•œ๋‹ค. ๋ฐ”๋กœ, logResponseBody() ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•ฑ์„ ํ•œ ๋ฒˆ ์‹คํ–‰ํ•ด์„œ ์–ป์–ด์ง„ Log ๋ฉ”์‹œ์ง€๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•˜๋‚˜์˜ ํŒŒ์ผ๋กœ ๋งŒ๋“ค์ž. ํ•ด๋‹น ํŒŒ์ผ์˜ ์ด๋ฆ„์€ album_response.json์œผ๋กœ ์ง“๋Š”๋‹ค. ์ด ์ž‘์—…์€ Mock ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•  Response๋ฅผ ํ•˜๋“œ ์ฝ”๋”ฉํ•˜๋ ค๋Š” ๋ชฉ์ ์ด๋‹ค.
 
album_response.json

๋”๋ณด๊ธฐ
[
  {
    "id": 1,
    "title": "quidem molestiae enim",
    "userId": 1
  },
  {
    "id": 2,
    "title": "sunt qui excepturi placeat culpa",
    "userId": 1
  },
  {
    "id": 3,
    "title": "omnis laborum odio",
    "userId": 1
  },
  {
    "id": 4,
    "title": "non esse culpa molestiae omnis sed optio",
    "userId": 1
  },
  {
    "id": 5,
    "title": "eaque aut omnis a",
    "userId": 1
  },
  {
    "id": 6,
    "title": "natus impedit quibusdam illo est",
    "userId": 1
  },
  {
    "id": 7,
    "title": "quibusdam autem aliquid et et quia",
    "userId": 1
  },
  {
    "id": 8,
    "title": "qui fuga est a eum",
    "userId": 1
  },
  {
    "id": 9,
    "title": "saepe unde necessitatibus rem",
    "userId": 1
  },
  {
    "id": 10,
    "title": "distinctio laborum qui",
    "userId": 1
  },
  {
    "id": 11,
    "title": "quam nostrum impedit mollitia quod et dolor",
    "userId": 2
  },
  {
    "id": 12,
    "title": "consequatur autem doloribus natus consectetur",
    "userId": 2
  },
  {
    "id": 13,
    "title": "ab rerum non rerum consequatur ut ea unde",
    "userId": 2
  },
  {
    "id": 14,
    "title": "ducimus molestias eos animi atque nihil",
    "userId": 2
  },
  {
    "id": 15,
    "title": "ut pariatur rerum ipsum natus repellendus praesentium",
    "userId": 2
  },
  {
    "id": 16,
    "title": "voluptatem aut maxime inventore autem magnam atque repellat",
    "userId": 2
  },
  {
    "id": 17,
    "title": "aut minima voluptatem ut velit",
    "userId": 2
  },
  {
    "id": 18,
    "title": "nesciunt quia et doloremque",
    "userId": 2
  },
  {
    "id": 19,
    "title": "velit pariatur quaerat similique libero omnis quia",
    "userId": 2
  },
  {
    "id": 20,
    "title": "voluptas rerum iure ut enim",
    "userId": 2
  },
  {
    "id": 21,
    "title": "repudiandae voluptatem optio est consequatur rem in temporibus et",
    "userId": 3
  },
  {
    "id": 22,
    "title": "et rem non provident vel ut",
    "userId": 3
  },
  {
    "id": 23,
    "title": "incidunt quisquam hic adipisci sequi",
    "userId": 3
  },
  {
    "id": 24,
    "title": "dolores ut et facere placeat",
    "userId": 3
  },
  {
    "id": 25,
    "title": "vero maxime id possimus sunt neque et consequatur",
    "userId": 3
  },
  {
    "id": 26,
    "title": "quibusdam saepe ipsa vel harum",
    "userId": 3
  },
  {
    "id": 27,
    "title": "id non nostrum expedita",
    "userId": 3
  },
  {
    "id": 28,
    "title": "omnis neque exercitationem sed dolor atque maxime aut cum",
    "userId": 3
  },
  {
    "id": 29,
    "title": "inventore ut quasi magnam itaque est fugit",
    "userId": 3
  },
  {
    "id": 30,
    "title": "tempora assumenda et similique odit distinctio error",
    "userId": 3
  },
  {
    "id": 31,
    "title": "adipisci laborum fuga laboriosam",
    "userId": 4
  },
  {
    "id": 32,
    "title": "reiciendis dolores a ut qui debitis non quo labore",
    "userId": 4
  },
  {
    "id": 33,
    "title": "iste eos nostrum",
    "userId": 4
  },
  {
    "id": 34,
    "title": "cumque voluptatibus rerum architecto blanditiis",
    "userId": 4
  },
  {
    "id": 35,
    "title": "et impedit nisi quae magni necessitatibus sed aut pariatur",
    "userId": 4
  },
  {
    "id": 36,
    "title": "nihil cupiditate voluptate neque",
    "userId": 4
  },
  {
    "id": 37,
    "title": "est placeat dicta ut nisi rerum iste",
    "userId": 4
  },
  {
    "id": 38,
    "title": "unde a sequi id",
    "userId": 4
  },
  {
    "id": 39,
    "title": "ratione porro illum labore eum aperiam sed",
    "userId": 4
  },
  {
    "id": 40,
    "title": "voluptas neque et sint aut quo odit",
    "userId": 4
  },
  {
    "id": 41,
    "title": "ea voluptates maiores eos accusantium officiis tempore mollitia consequatur",
    "userId": 5
  },
  {
    "id": 42,
    "title": "tenetur explicabo ea",
    "userId": 5
  },
  {
    "id": 43,
    "title": "aperiam doloremque nihil",
    "userId": 5
  },
  {
    "id": 44,
    "title": "sapiente cum numquam officia consequatur vel natus quos suscipit",
    "userId": 5
  },
  {
    "id": 45,
    "title": "tenetur quos ea unde est enim corrupti qui",
    "userId": 5
  },
  {
    "id": 46,
    "title": "molestiae voluptate non",
    "userId": 5
  },
  {
    "id": 47,
    "title": "temporibus molestiae aut",
    "userId": 5
  },
  {
    "id": 48,
    "title": "modi consequatur culpa aut quam soluta alias perspiciatis laudantium",
    "userId": 5
  },
  {
    "id": 49,
    "title": "ut aut vero repudiandae voluptas ullam voluptas at consequatur",
    "userId": 5
  },
  {
    "id": 50,
    "title": "sed qui sed quas sit ducimus dolor",
    "userId": 5
  },
  {
    "id": 51,
    "title": "odit laboriosam sint quia cupiditate animi quis",
    "userId": 6
  },
  {
    "id": 52,
    "title": "necessitatibus quas et sunt at voluptatem",
    "userId": 6
  },
  {
    "id": 53,
    "title": "est vel sequi voluptatem nemo quam molestiae modi enim",
    "userId": 6
  },
  {
    "id": 54,
    "title": "aut non illo amet perferendis",
    "userId": 6
  },
  {
    "id": 55,
    "title": "qui culpa itaque omnis in nesciunt architecto error",
    "userId": 6
  },
  {
    "id": 56,
    "title": "omnis qui maiores tempora officiis omnis rerum sed repellat",
    "userId": 6
  },
  {
    "id": 57,
    "title": "libero excepturi voluptatem est architecto quae voluptatum officia tempora",
    "userId": 6
  },
  {
    "id": 58,
    "title": "nulla illo consequatur aspernatur veritatis aut error delectus et",
    "userId": 6
  },
  {
    "id": 59,
    "title": "eligendi similique provident nihil",
    "userId": 6
  },
  {
    "id": 60,
    "title": "omnis mollitia sunt aliquid eum consequatur fugit minus laudantium",
    "userId": 6
  },
  {
    "id": 61,
    "title": "delectus iusto et",
    "userId": 7
  },
  {
    "id": 62,
    "title": "eos ea non recusandae iste ut quasi",
    "userId": 7
  },
  {
    "id": 63,
    "title": "velit est quam",
    "userId": 7
  },
  {
    "id": 64,
    "title": "autem voluptatem amet iure quae",
    "userId": 7
  },
  {
    "id": 65,
    "title": "voluptates delectus iure iste qui",
    "userId": 7
  },
  {
    "id": 66,
    "title": "velit sed quia dolor dolores delectus",
    "userId": 7
  },
  {
    "id": 67,
    "title": "ad voluptas nostrum et nihil",
    "userId": 7
  },
  {
    "id": 68,
    "title": "qui quasi nihil aut voluptatum sit dolore minima",
    "userId": 7
  },
  {
    "id": 69,
    "title": "qui aut est",
    "userId": 7
  },
  {
    "id": 70,
    "title": "et deleniti unde",
    "userId": 7
  },
  {
    "id": 71,
    "title": "et vel corporis",
    "userId": 8
  },
  {
    "id": 72,
    "title": "unde exercitationem ut",
    "userId": 8
  },
  {
    "id": 73,
    "title": "quos omnis officia",
    "userId": 8
  },
  {
    "id": 74,
    "title": "quia est eius vitae dolor",
    "userId": 8
  },
  {
    "id": 75,
    "title": "aut quia expedita non",
    "userId": 8
  },
  {
    "id": 76,
    "title": "dolorem magnam facere itaque ut reprehenderit tenetur corrupti",
    "userId": 8
  },
  {
    "id": 77,
    "title": "cupiditate sapiente maiores iusto ducimus cum excepturi veritatis quia",
    "userId": 8
  },
  {
    "id": 78,
    "title": "est minima eius possimus ea ratione velit et",
    "userId": 8
  },
  {
    "id": 79,
    "title": "ipsa quae voluptas natus ut suscipit soluta quia quidem",
    "userId": 8
  },
  {
    "id": 80,
    "title": "id nihil reprehenderit",
    "userId": 8
  },
  {
    "id": 81,
    "title": "quibusdam sapiente et",
    "userId": 9
  },
  {
    "id": 82,
    "title": "recusandae consequatur vel amet unde",
    "userId": 9
  },
  {
    "id": 83,
    "title": "aperiam odio fugiat",
    "userId": 9
  },
  {
    "id": 84,
    "title": "est et at eos expedita",
    "userId": 9
  },
  {
    "id": 85,
    "title": "qui voluptatem consequatur aut ab quis temporibus praesentium",
    "userId": 9
  },
  {
    "id": 86,
    "title": "eligendi mollitia alias aspernatur vel ut iusto",
    "userId": 9
  },
  {
    "id": 87,
    "title": "aut aut architecto",
    "userId": 9
  },
  {
    "id": 88,
    "title": "quas perspiciatis optio",
    "userId": 9
  },
  {
    "id": 89,
    "title": "sit optio id voluptatem est eum et",
    "userId": 9
  },
  {
    "id": 90,
    "title": "est vel dignissimos",
    "userId": 9
  },
  {
    "id": 91,
    "title": "repellendus praesentium debitis officiis",
    "userId": 10
  },
  {
    "id": 92,
    "title": "incidunt et et eligendi assumenda soluta quia recusandae",
    "userId": 10
  },
  {
    "id": 93,
    "title": "nisi qui dolores perspiciatis",
    "userId": 10
  },
  {
    "id": 94,
    "title": "quisquam a dolores et earum vitae",
    "userId": 10
  },
  {
    "id": 95,
    "title": "consectetur vel rerum qui aperiam modi eos aspernatur ipsa",
    "userId": 10
  },
  {
    "id": 96,
    "title": "unde et ut molestiae est molestias voluptatem sint",
    "userId": 10
  },
  {
    "id": 97,
    "title": "est quod aut",
    "userId": 10
  },
  {
    "id": 98,
    "title": "omnis quia possimus nesciunt deleniti assumenda sed autem",
    "userId": 10
  },
  {
    "id": 99,
    "title": "consectetur ut id impedit dolores sit ad ex aut",
    "userId": 10
  },
  {
    "id": 100,
    "title": "enim repellat iste",
    "userId": 10
  }
]

 

#2-3 resources ๋””๋ ‰ํ† ๋ฆฌ ๋งŒ๋“ค๊ธฐ ๋ฐ album_response.json ์ถ”๊ฐ€

์™ผ์ชฝ ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ๋ณด๊ธฐ ๋ชจ๋“œ๋ฅผ [Project]๋กœ ๋†“๊ณ , ๋ชจ๋“ˆ_์ด๋ฆ„/src/main ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์— resources ๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ(ํด๋”)๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฐฉ๊ธˆ ๋งŒ๋“  album_response.json์„ ์œ„์น˜์‹œํ‚จ๋‹ค.
 

#3 Unit Testing

#3-1 ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ์ƒ์„ฑ

๋‚ด๊ฐ€ ํ…Œ์ŠคํŠธํ•  ํด๋ž˜์Šค๋Š” AlbumService๋‹ค. ์ด๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ์— ์ด ๊ฒŒ์‹œ๊ธ€์˜ #3-1์—์„œ ์ง„ํ–‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ์ƒ์„ฑ์„ ํ•  ์ˆ˜๋Š” ์—†๋‹ค ([Generate...] ๋ฉ”๋‰ด ๋‹ค์Œ์œผ๋กœ [Test...] ๋ฉ”๋‰ด๊ฐ€ ์•ˆ ๋œธ). ํ•˜์ง€๋งŒ, ๊ทธ๋ƒฅ ์ง์ ‘ ์ˆ˜๋™์œผ๋กœ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ๊ทธ๋งŒ์ด๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ ์—๋ฎฌ๋ ˆ์ดํ„ฐ์— ์˜์กด์—†์ด ๋Œ์•„๊ฐ€๋Š” MockWebServer ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์— ๋•Œ๋ฌธ์— Local unit test๋กœ ์ง„ํ–‰ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, test ๋””๋ ‰ํ† ๋ฆฌ์— ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
 

#3-2 ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์˜ ๋‚ด์šฉ ์ž‘์„ฑ

import com.google.common.truth.Truth
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okio.buffer
import okio.source
import org.junit.After
import org.junit.Before
import org.junit.Test
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class AlbumServiceTest {

    private lateinit var service: AlbumService
    private lateinit var server: MockWebServer

    @Before
    fun setUp() {
        // Dependency (Test double) ์ดˆ๊ธฐํ™”
        server = MockWebServer()

        // Dependent ์ดˆ๊ธฐํ™”
        service = Retrofit.Builder()
            .baseUrl(server.url("")) // baseUrl (Mock์ด๋ผ์„œ baseUrl์„ ๊ตณ์ด ์ œ๋Œ€๋กœ ๋„ฃ์„ ํ•„์š” ์—†๋‹ค. ๋ญ˜ ๋„ฃ์–ด๋„ ํ•˜๋“œ ์ฝ”๋”ฉ๋œ response๋ฅผ ๋‚ด๋ฑ‰์„ ๊ฒƒ์ด๋‹ค.)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(AlbumService::class.java)
    }

    @After
    fun tearDown() {
        server.shutdown()
    }

    /* Server์— ํ•˜๋“œ์ฝ”๋”ฉ๋œ JSON ํŒŒ์ผ ๋„ฃ๊ธฐ.
     * server.enqueue(mockResponse)๋œ ์ˆœ๊ฐ„๋ถ€ํ„ฐ,
     * Server์— ๋ฌด์Šจ ์š”์ฒญ์„ ํ•˜๋“  mockResponse๋ฅผ ์‘๋‹ตํ•ด์คŒ.
     * ๋ฌผ๋ก  Queue์ด๋ฏ€๋กœ First In First Out์ด๊ณ ,
     * n๊ฐœ์˜ ์‘๋‹ต์ด ํ•„์š”ํ•˜๋‹ค๋ฉด server.enqueue()๋ฅผ n๋ฒˆํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
     */
    private fun enqueueMockResponse(fileName: String) {
        val inputStream = javaClass.classLoader!!.getResourceAsStream(fileName)
        val source = inputStream.source().buffer()
        val mockResponse = MockResponse()
        mockResponse.setBody(source.readString(Charsets.UTF_8))
        server.enqueue(mockResponse)
    }

    // ์˜ฌ๋ฐ”๋ฅธ request๋ฅผ ๋ณด๋‚ด๋Š” ์ง€, ์‘๋‹ต์ด ์˜ค๊ธดํ•˜๋Š” ์ง€ ํ™•์ธ
    @Test
    fun getAlbums_sentRequest_receivedExpected() { // subjectUnderTest_actionOrInput_resultState ๊ทœ์น™์œผ๋กœ ํ•จ์ˆ˜ ๋ช…๋ช…ํ•จ
        runBlocking {
            // Mock ์„œ๋ฒ„์— ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ฐ์ดํ„ฐ ๋„ฃ๊ณ , ๊ณง๋ฐ”๋กœ request ๋ฐ response ๋ฐ›๊ธฐ
            enqueueMockResponse("album_response.json")
            val responseBody = service.getAlbums().body()

            /* ์„œ๋ฒ„๊ฐ€ ๋ฐ›์€ HTTP request ๊ฐ€์ ธ์˜ค๊ณ , ์˜ฌ๋ฐ”๋ฅธ request์˜€๋Š”์ง€ ํ™•์ธ.
             * @Query ์–ด๋…ธํ…Œ์ด์…˜์ด ์กด์žฌํ•œ๋‹ค๋ฉด,
             * ์˜ˆ๋ฅผ ๋“ค์–ด "/albums?userId=7"์™€ ๊ฐ™์ด ์ ์–ด์•ผ ํ•œ๋‹ค.
             */
            val request = server.takeRequest()
            Truth.assertThat(request.path).isEqualTo(/* expected = */ "/albums")

            // response์ด null์ด ์•„๋‹˜์„ ํ™•์ธ (Mock ์„œ๋ฒ„๊ฐ€ ๋ญ๋ผ๋„ ์ž˜ ๋‚ด๋ฑ‰๋Š” ์ง€ ํ™•์ธ)
            Truth.assertThat(responseBody).isNotNull()
        }
    }

    // Albums์˜ ๊ฐฏ์ˆ˜ ํ™•์ธ
    @Test
    fun getAlbums_receivedResponse_correctElementSize() {
        runBlocking {
            // Mock ์„œ๋ฒ„์— ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ฐ์ดํ„ฐ ๋„ฃ๊ณ , ๊ณง๋ฐ”๋กœ request ๋ฐ response ๋ฐ›๊ธฐ
            enqueueMockResponse("album_response.json")
            val responseBody = service.getAlbums().body()

            Truth.assertThat(responseBody!!.size).isEqualTo(/* expected = */ 100)
        }
    }

    // ๋ชจ๋“  Albums๋ฅผ ๋‹ค ํ™•์ธํ•˜๋Š” ๊ฑด ์‹œ๊ฐ„๋„ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ณ  ํ•„์š”์„ฑ๋„ ํฌ์ง€ ์•Š์œผ๋‹ˆ, ์ฒซ๋ฒˆ์งธ ์•จ๋ฒ”๋งŒ ํ™•์ธ
    @Test
    fun getAlbums_receivedResponse_correctContent() {
        runBlocking {
            // Mock ์„œ๋ฒ„์— ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ฐ์ดํ„ฐ ๋„ฃ๊ณ , ๊ณง๋ฐ”๋กœ request ๋ฐ response ๋ฐ›๊ธฐ
            enqueueMockResponse("album_response.json")
            val responseBody = service.getAlbums().body()
            val firstAlbum = responseBody!![0]

            Truth.assertThat(firstAlbum.userId).isEqualTo(/* expected = */ 1)
            Truth.assertThat(firstAlbum.id).isEqualTo(/* expected = */ 1)
            Truth.assertThat(firstAlbum.title).isEqualTo(/* expected = */ "quidem molestiae enim")
        }
    }
}

 

#4 ์ž‘๋™ ํ™•์ธ

 

#5 ์™„์„ฑ๋œ ์•ฑ

 

android-practice/unit-test/TestingRetrofit at master · Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com