Upgrade to Pro — share decks privately, control downloads, hide ads and more …

테스트를 작성하고 활용하는 모든 과정 훑어보기

테스트를 작성하고 활용하는 모든 과정 훑어보기

2021.06.08 Naver 사내 TechTalk로 4시간 강의했던 자료입니다.

Seungmin 마량

June 08, 2021
Tweet

More Decks by Seungmin 마량

Other Decks in Programming

Transcript

  1. ੉थ޹ ߛ௼࢟۞٘ Frontend Engineering Manager / GDE Android Korea [email protected]

    పझ౟ܳ ੘ࢿೞҊ ഝਊೞח ݽٚ җ੿ വযࠁӝ
  2. పझ౟ۆ? যڃ ز੘ਸ ഐ୹೮ਸ ٸ, 1. ч੉ ਗೞח ഋకо غח૑

    Ѩૐ 2. ਗೞח ز੘ਸ ো҅೧ࢲ ࣻ೯ೞחо Ѩૐ
  3. class GithubRepoPresenter( view: GithubRepoView, repository: GithubRepository ) { fun issues(repo:

    GithubRepo) = repository.issues(owner, repo.name) .subscribe( { view.showIssues(it) }, { it.printStackTrace() } ) }
  4. class GithubRepoPresenter( view: GithubRepoView, repository: GithubRepository ) { fun issues(repo:

    GithubRepo) = repository.issues(owner, repo.name) .subscribe( { view.showIssues(it) }, { it.printStackTrace() } ) } ੄ઓ௿ېझ
  5. class GithubRepoPresenter( view: GithubRepoView, repository: GithubRepository ) { fun issues(repo:

    GithubRepo) = repository.issues(owner, repo.name) .subscribe( { view.showIssues(it) }, { it.printStackTrace() } ) } যڌѱز੘  ޖ঺ਸ߈ജ
  6. class GithubReposPresenterTest { private lateinit var presenter: GithubReposPresenter @Mock lateinit

    var view: GithubReposView @Mock lateinit var githubRepository: GithubRepository @Before fun setUp() { presenter = GithubReposPresenter( view, githubRepository ) } }
  7. class GithubReposPresenterTest { private lateinit var presenter: GithubReposPresenter @Mock lateinit

    var view: GithubReposView @Mock lateinit var githubRepository: GithubRepository @Before fun setUp() { presenter = GithubReposPresenter( view, githubRepository ) } } .PDLഝਊ
  8. // ߈ജ чਸ ૑੿ val repos: List<GithubRepo> = emptyList() //

    Mock Class੄ ز੘ਸ ੿੄ Mockito.`when`( githubRepository.searchGithubRepos(anyString()) ).thenReturn(Single.just(repos))
  9. // ߈ജ чਸ ૑੿ val repos: List<GithubRepo> = emptyList() //

    Mock Class੄ ز੘ਸ ੿੄ Mockito.`when`( githubRepository.searchGithubRepos(anyString()) ).thenReturn(Single.just(repos)) 4UVC .PDLJOH
  10. class GithubReposPresenter( private val connectivityManager: ConnectivityManager, ) : BasePresenter<GithubReposView>(view) {

    fun onCreate() { if (connectivityManager.isConnected().not()) view.showNoInternetWarning() } }
  11. class GithubReposPresenter( private val connectivityManager: ConnectivityManager, ) : BasePresenter<GithubReposView>(view) {

    fun onCreate() { if (connectivityManager.isConnected().not()) view.showNoInternetWarning() } } $POUFYU੄ઓೞח ੋఠ֔୓௼ӝמࢎਊ
  12. class GithubReposPresenter( private val connectivityManager: ConnectivityManager, ) : BasePresenter<GithubReposView>(view) {

    fun onCreate() { if (connectivityManager.isConnected().not()) view.showNoInternetWarning() } } @Test fun internetCheckTest() { Mockito.`when`(connectivityManagerMock.isConnected()).thenReturn(false) presenter.onCreate() Mockito.verify(view).showNoInternetWarning() }
  13. class GithubReposPresenter( private val connectivityManager: ConnectivityManager, ) : BasePresenter<GithubReposView>(view) {

    fun onCreate() { if (connectivityManager.isConnected().not()) view.showNoInternetWarning() } } @Test fun internetCheckTest() { Mockito.`when`(connectivityManagerMock.isConnected()).thenReturn(false) presenter.onCreate() Mockito.verify(view).showNoInternetWarning() } &SSPS উ٘۽੉٘੄ઓݫࣗ٘ࢎਊ
  14. class NetworkHelper(context: Context) { private val connectivityManager: ConnectivityManager fun isConnected():

    Boolean = connectivityManager.isConnected() } class GithubReposPresenter( private val networkHelper: NetworkHelper, ) : BasePresenter<GithubReposView>(view) { fun onCreate() { if (networkHelper.isConnected().not()) view.showNoInternetWarning() } }
  15. class NetworkHelper(context: Context) { private val connectivityManager: ConnectivityManager fun isConnected():

    Boolean = connectivityManager.isConnected() } class GithubReposPresenter( private val networkHelper: NetworkHelper, ) : BasePresenter<GithubReposView>(view) { fun onCreate() { if (networkHelper.isConnected().not()) view.showNoInternetWarning() } } $POUFYUӝמ 8SBQQJOH
  16. 1. ੄ઓ Class੄ ز੘ - Mocking, Stub 2. উ٘۽੉٘ ੄ઓ

    ز੘ - Wrapping, Mocking పझ౟ܳ য۵ѱ ೞח Ѫ
  17. 1. ੄ઓ Class੄ ز੘ - Mocking, Stub 2. উ٘۽੉٘ ੄ઓ

    ز੘ - Wrapping, Mocking పझ౟ܳ য۵ѱ ೞח Ѫ ਤޙઁоऔѱ೧䟽غযঠపझ౟ܳೡࣻ੓׮
  18. 1. ੄ઓ Class੄ ز੘ - Mocking, Stub 2. উ٘۽੉٘ ੄ઓ

    ز੘ - Wrapping, Mocking పझ౟ܳ য۵ѱ ೞח Ѫ ਤޙઁоऔѱ೧䟽غযঠపझ౟ܳೡࣻ੓׮ 5FTUBCMF"SDIJUFDUVSF
  19. ௏٘੄ ৉ೡਸ ܻ࠙ೞৈ ৈ۞ ੉੼ਸ ঳ח׮ 1. оةࢿ (֫਷ ਽૘ب)

    2. ߸҃ ਬোೣ (ծ਷ Ѿ೤ب) উ٘۽੉٘ীࢲח MVP, MVVMਸ ઱۽ ࢎਊ Architectureۆ?
  20. ௏٘੄ ৉ೡਸ ܻ࠙ೞৈ ৈ۞ ੉੼ਸ ঳ח׮ 1. оةࢿ (֫਷ ਽૘ب)

    2. ߸҃ ਬোೣ (ծ਷ Ѿ೤ب) উ٘۽੉٘ীࢲח MVP, MVVMਸ ઱۽ ࢎਊ Architectureۆ? Ӓրࢎਊೞݶ/PU5FTUBCMFഛܫ੉֫਺ ݻਗ஗ਸӝ߈ਵ۽ѐ䣜ೞݶ5FTUBCMF"SDIJUFDUVSF
  21. class GithubRepoBadPresenter( view: GithubRepoView ) : BasePresenter<GithubRepoView>(view) { private val

    repository = GithubRepository() fun save(repo: GithubRepo) = repository.save(repo) .subscribe() } Bad Case 1 - ੄ઓࢿ ࢤࢿ
  22. class GithubRepoBadPresenter( view: GithubRepoView ) : BasePresenter<GithubRepoView>(view) { private val

    repository = GithubRepository() fun save(repo: GithubRepo) = repository.save(repo) .subscribe() } ੄ઓࢿ੗୓ࢤࢿ Bad Case 1 - ੄ઓࢿ ࢤࢿ
  23. class GithubRepoBadPresenter( view: GithubRepoView ) : BasePresenter<GithubRepoView>(view) { private val

    repository = GithubRepository() fun save(repo: GithubRepo) = repository.save(repo) .subscribe() } .PDL3FQPTJUPSZ઱ੑࠛо పझ౟ࠛо Bad Case 1 - ੄ઓࢿ ࢤࢿ
  24. class GithubRepoGoodPresenter( view: GithubRepoView, private val repository: GithubRepository ) :

    BasePresenter<GithubRepoView>(view) class GithubRepoPresenterTest : BasePresenterTest() { @Mock lateinit var githubRepository: GithubRepository override fun setUp() { presenter = GithubRepoPresenter( view, githubRepository ) } Good Case
  25. class GithubRepoGoodPresenter( view: GithubRepoView, private val repository: GithubRepository ) :

    BasePresenter<GithubRepoView>(view) class GithubRepoPresenterTest : BasePresenterTest() { @Mock lateinit var githubRepository: GithubRepository override fun setUp() { presenter = GithubRepoPresenter( view, githubRepository ) } Good Case ੄ઓࢿ઱ੑ߉਺
  26. class GithubRepoGoodPresenter( view: GithubRepoView, private val repository: GithubRepository ) :

    BasePresenter<GithubRepoView>(view) class GithubRepoPresenterTest : BasePresenterTest() { @Mock lateinit var githubRepository: GithubRepository override fun setUp() { presenter = GithubRepoPresenter( view, githubRepository ) } Good Case .PDLഝਊ పझ౟оמ
  27. class GithubRepoActivity { override val presenter: GithubRepoPresenter by lazy {

    GithubRepoPresenter(this, GithubRepository()) } } ࠗ۾
  28. class GithubRepoActivity { override val presenter: GithubRepoPresenter by lazy {

    GithubRepoPresenter(this, GithubRepository()) } } ࠗ۾ 6*ী䞵%BUBଵઑ
  29. class GithubRepoActivity { override val presenter: GithubRepoPresenter by lazy {

    GithubRepoPresenter(this, GithubRepository()) } } ࠗ۾ 6*ী䞵%BUBଵઑ  %*
  30. class IssueCreatePresenter { fun createIssue(repo: GithubRepo, title: String, body: String)

    = repository.createIssue(owner, name, title, body) .subscribe({ DataObserver.post(it) view.onIssueCreated() }, { view.onIssueCreateFail() }) } Bad Case 2 - Static Class
  31. class IssueCreatePresenter { fun createIssue(repo: GithubRepo, title: String, body: String)

    = repository.createIssue(owner, name, title, body) .subscribe({ DataObserver.post(it) view.onIssueCreated() }, { view.onIssueCreateFail() }) } 4UBUJD$MBTT ઱ੑࠛоపझ౟ࠛо Bad Case 2 - Static Class
  32. class IssueCreatePresenter( view: IssueCreateView, private val dataObserver: DataObserver, private val

    repository: GithubRepository ) Good Case 4UBUJD$MBTTܳੌ߈$MBTT۽߸҃ ੄ઓࢿ઱ੑ߉਺
  33. class NetworkHelper(context: Context) { private val connectivityManager: ConnectivityManager fun isConnected():

    Boolean = connectivityManager.isConnected() } class GithubReposPresenter( private val networkHelper: NetworkHelper, ) : BasePresenter<GithubReposView>(view) { fun onCreate() { if (networkHelper.isConnected().not()) view.showNoInternetWarning() } } $POUFYUӝמ 8SBQQJOH SDK Method
  34. interface GithubReposView { fun showNoInternetWarning() fun showLoading() fun hideLoading() fun

    showRepos(repos: List<GithubRepo>) } fun onCreate() { if (networkHelper.isConnected().not()) view.showNoInternetWarning() } UI Method
  35. interface GithubReposView { fun showNoInternetWarning() fun showLoading() fun hideLoading() fun

    showRepos(repos: List<GithubRepo>) } fun onCreate() { if (networkHelper.isConnected().not()) view.showNoInternetWarning() } 7JFX*OUFSGBDF۽ 8SBQQJOH UI Method
  36. interface GithubRepository { fun save(repo: GithubRepo): Completable fun star(owner: String,

    repo: String): Completable fun unstar(owner: String, repo: String): Completable } class IssueCreatePresenter( private val repository: GithubRepository ) { fun createIssue(repo: GithubRepo, title: String, body: String) = repository.createIssue(owner, repo.name, title, body) .subscribe{ view.onIssueCreated() } } DB / API ాन
  37. interface GithubRepository { fun save(repo: GithubRepo): Completable fun star(owner: String,

    repo: String): Completable fun unstar(owner: String, repo: String): Completable } class IssueCreatePresenter( private val repository: GithubRepository ) { fun createIssue(repo: GithubRepo, title: String, body: String) = repository.createIssue(owner, repo.name, title, body) .subscribe{ view.onIssueCreated() } } DB / API ాन 3FQPTJUPSZ*OUFSGBDF۽ 8SBQQJOH
  38. ਗ஗ 2 - উ٘۽੉٘ ੄ઓ ز੘ਸ Wrapping ೠ׮ 4%,.FUIPE6*%# "1*ాन

    4%,.FUIPE8SBQQFS 7JFX*OUFSGBDF 3FQPTJUPSZ .71੄ӝࠄ
  39. override fun onCreate(savedInstanceState: Bundle?) { showRepo(intent.getParcelableExtra<GithubRepo>(KEY_REPO)) } private fun showRepo(repo:

    GithubRepo) { ownerName.text = repo.owner.userName starCount.text = repo.stargazersCount.toString() watcherCount.text = repo.watchersCount.toString() forksCount.text = repo.forksCount.toString() showStar(repo.star) presenter.issues(repo) } Bad Case 1 - ചݶ ղ private Method
  40. override fun onCreate(savedInstanceState: Bundle?) { // showRepo(intent.getParcelableExtra<GithubRepo>(KEY_REPO)) } private fun

    showRepo(repo: GithubRepo) { ownerName.text = repo.owner.userName starCount.text = repo.stargazersCount.toString() watcherCount.text = repo.watchersCount.toString() forksCount.text = repo.forksCount.toString() showStar(repo.star) presenter.issues(repo) } ഐ୹ৈࠗపझ౟ࠛо Bad Case 1 - ചݶ ղ private Method
  41. override fun onCreate(savedInstanceState: Bundle?) { presenter.onCreate(it) } fun onCreate(repo: GithubRepo)

    { this.repo = repo view.showRepo(repo) issues(repo) } Good Case 1SFTFOUFSী䞵۽૒ࣻ೯ 7JFXח1SFTFOUFSप೯݅
  42. star.onClick { val originalStar = repo.star showStar(!originalStar) showStarCount(repo.stargazersCount.let { if

    (originalStar) it - 1 else it + 1 }) presenter.onClickStar() } fun onClickStar() { (if (originalStar) repository.unstar(owner, repo.name) else repository.star(owner, repo.name)) ... } Bad Case 2 - ചݶ ղ ۽૒
  43. star.onClick { val originalStar = repo.star showStar(!originalStar) showStarCount(repo.stargazersCount.let { if

    (originalStar) it - 1 else it + 1 }) presenter.onClickStar() } fun onClickStar() { (if (originalStar) repository.unstar(owner, repo.name) else repository.star(owner, repo.name)) ... } Bad Case 2 - ചݶ ղ ۽૒ ഐ୹ৈࠗపझ౟ࠛо
  44. star.onClick { presenter.onClickStar() } fun onClickStar() { val originalStar =

    repo.star view.showStar(!originalStar) view.showStarCount(repo.stargazersCount.let { if (originalStar) it - 1 else it + 1 }) (if (originalStar) repository.unstar(owner, repo.name) else repository.star(owner, repo.name)) ... } Good Case
  45. star.onClick { presenter.onClickStar() } fun onClickStar() { val originalStar =

    repo.star view.showStar(!originalStar) view.showStarCount(repo.stargazersCount.let { if (originalStar) it - 1 else it + 1 }) (if (originalStar) repository.unstar(owner, repo.name) else repository.star(owner, repo.name)) ... } Good Case 1SFTFOUFSী䞵۽૒ࣻ೯ 7JFXח1SFTFOUFSप೯݅
  46. @Test fun clickStarTest() { repo.star = false val originalStarCount =

    repo.stargazersCount presenter.onClickStar() Mockito.verify(view).showStar(true) Mockito.verify(view).showStarCount(originalStarCount + 1) } Good Case 1SFTFOUFS۽૒పझ౟оמ
  47. @RunWith(AndroidJUnit4::class) class PreferenceTest { @Test fun preferenceTest() { val context

    = InstrumentationRegistry.getInstrumentation().context val pref = context.getSharedPreferences("preference") val userName = pref.getString("pref_user_name", "userName") assertEquals("userName", userName) } } $POUFYUദٙ
  48. ਗ஗ 1. ੄ઓࢿ ё୓ח ݽف ઱ੑ߉ח׮ 2. উ٘۽੉٘ ੄ઓ ز੘ਸ

    Wrapping ೠ׮ 3. ݽٚ ز੘਷ Presenterܳ ాೠ׮
  49. ޖ঺ਸ పझ౟ ೧ঠೡө .FUIPEܳ5FTU Methodח 1ѐ੄ ݾ੸݅ ࣽࣻೞѱ ࣻ೯ ->

    Aܳ ߉ਵݶ ঱ઁա Bܳ Return -> ೣࣻഋ ೐۽Ӓې߁ Aܳ ߄Լоݴ Bܳ Ѩૐ
  50. 1. ੄ઓ Class੄ ز੘ - Mocking, Stub 2. উ٘۽੉٘ ੄ઓ

    ز੘ - Wrapping, Mocking పझ౟ܳ য۵ѱ ೞח Ѫ
  51. 1. ੄ઓ Class੄ ز੘ - Mocking, Stub 2. উ٘۽੉٘ ੄ઓ

    ز੘ - Wrapping, Mocking పझ౟ܳ য۵ѱ ೞח Ѫ పझ౟੄ബਊࢿਸݽܰѷ׮ زӝо࢓૑ঋח׮
  52. 1. ز੘ ഛੋ 2. ߸҃ ਬোࢿ ഛࠁ 3. ௏ܻ٘࠭ܳ ذח׮

    పझ౟੄ ബਊࢿ పझ౟ח੄بܳݺदച పझ౟ܳ౵ঈೞҊ௏٘ܳࠁݶܻ࠭оࣻ䤰ೞ׮
  53. 1. ܻನ౟۽ അपਸ ӵײ੗ 2. ੊ࣼ೧૑ӝө૑ ъઁࢿਸ ف੗ 3. ए਍

    Ѫࠗఠ ରӔରӔ పझ౟ زӝࠗৈ 1SFTFOUFS7.5FTU 6OJU5FTU 6OJU5FTUо ࣘبоࡅܰҊ ࣻݺ੉ӡ׮