Skip to content

Latest commit

ย 

History

History
139 lines (89 loc) ยท 6.96 KB

File metadata and controls

139 lines (89 loc) ยท 6.96 KB

Episode 23. Mocking Part 1

์š”์•ฝ
Dummy
- interface์˜ ๋ชจ๋“  ๋ฉ”์†Œ๋“œ๋“ค์ด `return null;`๋กœ ๊ตฌํ˜„๋œ ํ…Œ์ŠคํŠธ ๋”๋ธ”

Stub
- dummy์˜ ์ผ์ข…. 0์ด๋‚˜ null ๋Œ€์‹  ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ํŠน์ • ๊ฐ’์„ ๋ฐ˜ํ™˜

Spy
- stub์˜ ์ผ์ข…. ์ž์‹ ์ด ํ˜ธ์ถœ๋œ fact๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ํ›„์— ํ…Œ์ŠคํŠธ์— ์ด๋Ÿฌํ•œ fact๋ฅผ ๋ณด๊ณ 
  - ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€, ์–ธ์ œ, ๋ช‡๋ฒˆ, ์–ด๋–ค ์ธ์ž๋กœ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ๋“ฑ

Mock
- spy์˜ ์ผ์ข…. ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜์•ผ ํ•˜๋Š”์ง€๋ฅผ ์•„๋Š” spy

Fake
- simulator
- ์‹ค์„ธ๊ณ„ ๊ฐ์ฒด๊ฐ€ ํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์‘๋‹ต์„ ํ•จ.
- ๋ณต์žก๋„์™€ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์œ„ํ•ด์„œ ๊ฐ€๊ธ‰์  ํ”ผ์• ํ– ํ•จ

mocking library๋ฅผ ์•ˆ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค.

Boundaries and Mocks

  • user๊ฐ€ loginํ•˜๋ฉด controller๊ฐ€ user name๊ณผ password๋ฅผ ๊ฐ„๋‹จํ•œ DS(LoginRequest)์— ๋‹ด์•„์„œ LoginInteractor์— ์ „๋‹ฌํ•œ๋‹ค.
  • LoginInteractor๋Š” user name๊ณผ password๋ฅผ ๊ฐ€์ง€๊ณ  authorizer๋ฅผ ํ†ตํ•ด ํ™•์ธํ•œ๋‹ค.
  • Authorizer๊ฐ€ user๋ฅผ acceptํ•˜๋ฉด Authorizer๋Š” valid user id๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • LoginInteractor๋Š” UserGateway๋ฅผ ์‚ฌ์šฉํ•ด์„œ User ๋น„์ฆˆ๋‹ˆ์ฆˆ ๊ฐ์ฒด๋ฅผ fetchํ•˜๊ณ , ๋งˆ์ง€๋ง‰ ๋กœ๊ทธ์ธ ์‹œ๊ฐ„, ๋กœ๊ทธ์ธ ํšŸ์ˆ˜ ๋“ฑ์„ ์–ป๋Š”๋‹ค.
  • LoginInteractor ๋Š” ์ด๋Ÿฌํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋˜ ๋‹ค๋ฅธ ๋‹จ์ˆœํ•œ DS(LoginResponse)๋ฅผ ํ†ตํ•ด LoginPresenter์— ์ „๋‹ฌํ•œ๋‹ค.
  • LoginPresenter๋Š” ํ™”๋ฉด์— ๋ณด์ผ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•œ๋‹ค.

LoginInteractor์— ๋Œ€ํ•œ ์ž๋™ํ™” ํ…Œ์ŠคํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ธ๊ฐ€ ?

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‰ฝ๊ฒŒ ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

  • setup์—์„œ User๋ฅผ ์ƒ์„ฑ. username, password๋ฅผ ๋ถ€์—ฌ
  • user record๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ last login time๊ณผ login ํšŸ์ˆ˜๋ฅผ ๊ฐ–๋„๋ก ํ•œ๋‹ค.

์ด์™€ ๊ฐ™์ด DB๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ๋А๋ ค์ง„๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์›น์˜ ๊ฒฝ์šฐ๋Š” HTML์„ ๊ธ์–ด์„œ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. UI๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋งˆ๋‹ค ํ…Œ์ŠคํŠธ๊ฐ€ ๊นจ์ง€๊ฒŒ ๋œ๋‹ค. ๋˜ ํ…Œ์ŠคํŠธ๋ฅผ ์›น์„œ๋ฒ„์—์„œ ์ˆ˜ํ–‰ํ•ด์•ผ๋งŒ ํ•œ๋‹ค. ์ด๊ฑด ์ •๋ง ๋А๋ฆฌ๋‹ค. ์ฐจ๋ผ๋ฆฌ ์ˆ˜๋™ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š”๊ฒŒ ๋‚ซ๋‹ค.

Mocking์„ ์ด์šฉํ•˜๋ฉด ํ•ด์†Œ๋œ๋‹ค. DB์— ์—ฐ๊ฒฐํ•  ํ•„์š”๋„ ์—†๊ณ , ์›น์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋„ ์—†๋‹ค. ๋˜ HTML์„ ๊ธ์–ด์„œ ํ™•์ธํ•  ํ•„์š”๋„ ์—†๋‹ค. mocking์ด ์ˆ˜์›”ํ•˜๋„๋ก nice clean decoupled ์•„ํ‚คํ…์ณ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

์œ„ ๊ทธ๋ฆผ์—์„œ ๋นจ๊ฐ„์„  ๋‚ด๋ถ€์— Interactor์™€ Interactor๊ฐ€ ์ž์‹ ์˜ ์ผ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ๋ชจ๋“  ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ด ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด๋“ค์€ authorizing, DB access, presentation ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ํ…Œ์ŠคํŠธํ•  ๋•Œ๋Š” ์ด๋Ÿฌํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋‹ค๋ฅธ ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ๋•๋Š” ๊ตฌํ˜„์ฒด... ์ด๊ฒƒ์ด Mocking์ด๋‹ค.

ํ…Œ์ŠคํŠธ์—์„œ ๊ฐœ๋ณ„์ ์œผ๋กœ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด stub์„ ์ƒ์„ฑํ•œ๋‹ค.

  • UserId(1)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” StubAuthorizer
  • InvalidUserID๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” RejectingAuthorizerStub

๋“ฑ์„ ๋งŒ๋“ค์–ด ๋†“๊ณ  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋งˆ๋‹ค ์ ์ ˆํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

LoginInteractorImpl์— setAuthorizer, setUserGateway๋Š” ์žˆ๊ณ , ์ด๋“ค์— ๋Œ€ํ•œ stub์ด ํ•„์š”ํ•˜์ง€๋งŒ presenter๋Š” ๋‹ค๋ฅด๋‹ค๊ณ  ํ•œ๋‹ค. presenter์— ๋Œ€ํ•ด์„œ๋Š” ์ ์ ˆํ•œ ์‹œ๊ธฐ์— ์ ์ ˆํ•œ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€๋งŒ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค. - interactor์˜ presenter์— ๋Œ€ํ•œ relationship์„ spyํ•˜๊ธฐ ์›ํ•œ๋‹ค.

  • stub์€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ • ๊ฐ€๋Šฅ
  • spy๋Š” ์ถ”๊ฐ€์ ์œผ๋กœ ์–ด๋–ค ์ธ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์•˜๋Š”์ง€๋ฅผ ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ์ „๋‹ฌ๋ฐ›์€ ์ธ์ž๋ฅผ assertํ•  ์ˆ˜ ์žˆ์Œ.

Test Doubles

The Dummy

๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ…Œ์ŠคํŠธ ๋”๋ธ”. interface์— ์žˆ๋Š” ๋ชจ๋“  ๋ฉ”์†Œ๋“œ๋ฅผ do nothing์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ Dummy. ๋ฆฌํ„ดํ•˜๋Š” ๊ฐ’์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ๋Œ€๊ฐœ null์ด๋‚˜ 0์„ ๋ฐ˜ํ™˜

public class HourlyReportInteractor {
  public void generateReport(Date reportDate, Session session) {
    if (!isValidReportDate(reportDate))
      throw new InvalidDate();
    //...
  }

์œ„ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

  @Test(expected = HourlyReportInteractor.InvalidDate.class)
  public void testInvalidDate() throws Exception {
    Date reportDate = null;
    Session session = new DummySession();
    interactor.generateReport(reportDate, session);
  }

DummySession - Session์€ ์ƒ์„ฑํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฐ์ฒด์ด๋‹ค. - reportDate๊ฐ€ invalidํ•œ ๊ฒฝ์šฐ session์€ ์‚ฌ์šฉ๋˜์ง€๋„ ์•Š๋Š”๋‹ค. - DummySession์„ ์ด์šฉํ•œ๋‹ค(๋ชจ๋“  method์—์„œ return null) - ์ด๋Ÿฐ ๊ฒฝ์šฐ Dummy๊ฐ€ ํšจ์œจ์ ์ด๋‹ค.

ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์ธ์ž๋ฅผ ๊ฐ–๋Š”๋ฐ ํ…Œ์ŠคํŠธ๋‚˜ ํ…Œ์ŠคํŠธ๋˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์ธ์ž์™€ ๋ฌด๊ด€ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

Dummy๋Š” ํ…Œ์ŠคํŠธ ๋”๋ธ”์˜ ์ผ์ข…์œผ๋กœ ์–ด๋–ค ์•ก์…˜๋„ ์ทจํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋“ค๋กœ ์ด๋ค„์ง„๋‹ค.

The Stub

stub์€ dummy์˜ ์ผ์ข…์ด๋‚˜ null, 0์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹  ํŠน์ • ํ…Œ์ŠคํŠธ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

stub์€ dummy์ด๋‹ค. ํ•จ์ˆ˜์—์„œ ์–ด๋–ค ์ผ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ 0์ด๋‚˜ null ๋Œ€์‹  ์–ด๋–ค ์š”๊ตฌ๋˜๋Š” ๊ณ ์ •๋œ ํŠน๋ณ„ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์ง€๋งŒ ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

stub์€ ํŠน์ • ๊ฒฝ๋กœ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์ˆ˜ํ–‰๋˜๋„๋ก ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

login interactor์˜ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๋•Œ์˜ ํ–‰์œ„๋ฅผ ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธํ•  ๊ฒƒ์ธ๊ฐ€ ? authenticator๋ฅผ stubํ•ด์„œ false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์—ฌ interactor๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํ–‰์œ„๋ฅผ ํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ…Œ์ŠคํŠธ์™€ stub ๊ฐ„์—๋Š” ๋Œ€์‘ ๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•œ๋‹ค. ํ…Œ์ŠคํŠธ๋Š” ์ ์ ˆํ•œ ๊ฒฝ๋กœ๋กœ ์ˆ˜ํ–‰๋˜๋„๋ก ํ•˜๋Š” stub๋ฅผ ์„ ํƒํ•˜๋„๋ก ์ž‘์„ฑ๋œ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ํŒจ์Šค์›Œ๋“œ๋กœ login์ด ์„ฑ๊ณตํ•˜๋Š”์ง€ ์กฐ์‚ฌํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” stub์„ ์‚ฌ์šฉํ•˜๊ณ , ์ž˜๋ชป๋œ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” login์„ ์กฐ์‚ฌํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” stub์„ ์‚ฌ์šฉํ•œ๋‹ค.

The Spy

spy๋Š” stub์ด๋‹ค. spy๋Š” ์ž์‹ ์ด ํ˜ธ์ถœ๋œ ํŠน๋ณ„ํ•œ fact๋ฅผ ๊ธฐ์–ตํ•˜๊ณ , ํ›„์— ํ…Œ์ŠคํŠธ์— ์ด๋Ÿฌํ•œ fact๋ฅผ ๋ณด๊ณ ํ•œ๋‹ค.

  • ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€
  • ๊ทธ ํ•จ์ˆ˜๊ฐ€ ์–ธ์ œ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€
  • ๋ช‡๋ฒˆ์ด๋‚˜ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€
  • ์–ด๋–ค ์ธ์ž๊ฐ€ ์ „๋‹ฌ๋˜์—ˆ๋Š”์ง€

๋ฅผ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

production ์ฝ”๋“œ๊ฐ€ ์™ธ๋ถ€ ์„œ๋น„์Šค๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ํ˜ธ์ถœํ•˜์˜€๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๊ณ ์ž ํ•  ๋•Œ ์œ ์šฉํ•œ ๊ธฐ๋ฒ•์ด๋‹ค.

The Mock

Mock์€ Spy์ด๊ณ  ์ถ”๊ฐ€์ ์œผ๋กœ

  • ํ…Œ์ŠคํŠธ์— ์œ ์šฉํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ 
  • ํ˜ธ์ถœ๋œ fact๋“ค์— ๋Œ€ํ•ด์„œ ๊ธฐ์–ตํ•œ๋‹ค.
  • ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜์•ผ ํ•˜๋Š”์ง€๋ฅผ ์•„๋Š” Spy์ด๋‹ค.

The Fake

๋งˆ์ง€๋ง‰ ํ…Œ์ŠคํŠธ ๋”๋ธ”์€ Fake์ด๋‹ค. Fake๋Š” dummy๋„ stub๋„ spy๋„ mock๋„ ์•„๋‹Œ Simulator์ด๋‹ค.

์‹ค์„ธ๊ณ„ ๊ฐ์ฒด๊ฐ€ ํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์‘๋‹ต์„ ํ•œ๋‹ค.

fake๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋ณต์žกํ•ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค. Test์—์„œ ํ•„์š”ํ•œ fake๋งŒ ์ž‘์„ฑํ•˜๋„๋ก ํ•œ๋‹ค.

avoid fakes when you can

๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ๋Š” fake๊นŒ์ง€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๋‹ค. ํ•˜์ง€๋งŒ integration test์—์„œ๋Š” fake๊ฐ€ ์œ ์šฉํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.