๐Ÿงช Test Driven Development

Kiwoong Kwon

2019. 10. 19.

Chapter 1 ~ 3

Table Of Contents

  1. Prerequisites

    1. eXtreme Programming

    2. Terminologies

    3. TDD Discipline

  2. Into the book

    1. ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

    2. ํƒ€๋ฝํ•œ ๊ฐ์ฒด

    3. ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

ย  ย  ย  ๐Ÿงช Prerequisites

TDDย 

์ด ์˜์ƒ์—์„œ ๋ฌด์—‡์ด ๊ฐ€์žฅ ํ™ฉ๋‹นํ•˜์…จ๋‚˜์š”?

ย  ย  ย  ๐Ÿงช Prerequisites

์ •๋‹ต์€ ํ…Œ์ŠคํŠธ ์—†์ด ๊ตฌ๊ตฌํด๋ž˜์Šค๋ฅผ ์ฝ”๋”ฉํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค

(ํ˜น์‹œ ํ…Œ์ŠคํŠธ ์งœ์„œ ์ฝ”๋“œ๊ฐ€ ๋ฌด๊ฑฐ์›Œ์งˆ๊ฑธ ๋Œ€๋น„ํ•œ๊ฑด...?)

ย  ย  ย  ๐Ÿงช Prerequisites

Q: ์•„๋‹ˆ ๊ตฌ๊ตฌ๋‹จ ํ”„๋กœ๊ทธ๋žจ ๊ฐ™์€๊ฒƒ๋„ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ตฌ์š”?

A: ๊ทธ๋Ÿผ์š”. "ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ" ์—์„œ๋Š” ๋ง์ด์ฃ 

ย  ย  ย  ๐Ÿงช eXtreme Programming

๊ทธ๋Ÿผ TDD ๋Š” ์–ด๋””์„œ ์™”๋Š๋ƒ...

ํƒœ์ดˆ์— eXtreme Programming ์ด ์žˆ์—ˆ๋‹ค

ย  ย  ย  ๐Ÿงช eXtreme Programming

XP๊ฐ€ ํ•˜๊ณ ์‹ถ์€ ๊ฒƒ? ๊ณ ๊ฐ์—๊ฒŒ ๊ฐ€์น˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ!

TDD, Pair Programming, Stand up, CI/CD ๋Š” ์‹ค์ฒœ๋ฐฉ๋ฒ•์— ๋ถˆ๊ณผ

TDD

Software Lifecycle (Cascade model)

Software Lifecycle (Prototype model)

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ๋Š” SDLC ์ข…๋‹จ์—์„œ

"์„ค๊ณ„ํ•œ ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š”์ง€" ๋ฅผ ํ™•์ธํ•˜๋Š” ์ž‘์—…

ย 

ํšŒ์‚ฌ์—์„œ๋Š” QA/QC ์ž‘์—…์— ํ•ด๋‹น

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ ๋˜ํ•œ ํ•˜๋‚˜์˜ ์—…๋ฌด ๋ถ„์•ผ๋กœ

๋ฐฐ๊ฒฝ ์ง€์‹์œผ๋กœ ์•Œ์•„์•ผ ํ•  ์šฉ์–ด๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‘

๋„ˆ๋ฌด ๋งŽ์œผ๋‹ˆ๊นŒ ํ•„์š”ํ•œ ๊ฒƒ๋งŒ...

๐Ÿ“– Acceptance Testing

์‹ค์ œ ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ์—์„œ, ์‚ฌ์šฉ์ž์— ๋น™์˜ ํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ ํ•จ.

์‚ฌ์šฉ์ž๊ฐ€ ๋งŒ์กฑํ• ๋งŒํ•œ ์ œํ’ˆ์œผ๋กœ ์ธ์ˆ˜(Accept) ํ•  ์˜ํ–ฅ์ด ์žˆ๋Š”์ง€๋ฅผ

์š”๊ตฌ์‚ฌํ•ญ ๋ช…์„ธ๋ฅผ ํ†ตํ•ด ํ…Œ์ŠคํŠธ

: ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ

๐Ÿ“– Assertion

๋‹จ์–ธ๋ฌธ์ด ์„ ์–ธ๋œ ์ง€์ ์—์„œ ๋ฐ˜๋“œ์‹œ ์ฐธ(true) ์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š”

์‚ฌํ•ญ์„ ํ‘œํ˜„ํ•œ ๋…ผ๋ฆฌ์‹์ด๋‹ค. ๋‹จ์–ธ๋ฌธ์— ์œ„๋ฐ˜๋˜๋Š” ๊ฒฝ์šฐ๋Š” ํ”„๋กœ๊ทธ๋žจ์—

๋ฒ„๊ทธ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ„์ฃผํ•œ๋‹ค

: ๋‹จ์–ธ

๐Ÿ“– Behavior Testing

ํ…Œ์ŠคํŒ… ๊ธฐ์ˆ  ์ค‘ ํ…Œ์ŠคํŠธ ๋”๋ธ” (๋’ค์—์„œ ์„ค๋ช…) ๊ณผ ํ˜‘๋ ฅํ•˜์—ฌ

์›ํ•˜๋Š” method ์ •ํ™•ํ•œ ์ˆœ์„œ๋กœ ์ •ํ™•ํ•œ ์ธ์ž์™€ ํ•จ๊ป˜ ํ˜ธ์ถœ ํ•˜์˜€๋Š”์ง€๋ฅผ

๊ฒ€์ฆํ•œ๋‹ค

: ํ–‰์œ„ ๊ฒ€์ฆ

๐Ÿ“– Behavior-Driven Development (BDD)

TDD์˜ subset ์œผ๋กœ, ์š”๊ตฌ์‚ฌํ•ญ.equals(ํ…Œ์ŠคํŠธ์ผ€์ด์Šค) ๊ฐ€ ๋œ๋‹ค๋Š”

์ ์„ ํ•ต์‹ฌ๊ฐœ๋…์œผ๋กœ ํ•œ๋‹ค. ๊ธฐ์ˆ ์ ์ธ ์ง€์‹์ด ์—†๋Š” ๊ด€๊ณ„์ž ๋˜ํ•œ ํ…Œ์ŠคํŠธ

์ผ€์ด์Šค์— ์‚ฌ์šฉ๋  ์‚ฌ์–‘์„ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ฝ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค

: ํ–‰์œ„ ์ฃผ๋„ ๊ฐœ๋ฐœ

๐Ÿ“– Black-Box Testing

์†Œํ”„ํŠธ์›จ์–ด ๊ฒ€์‚ฌ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ ์–ด๋–ค ์†Œํ”„ํŠธ์›จ์–ด ๋‚ด๋ถ€ ๊ตฌ์กฐ๋‚˜ ์ž‘๋™

์›๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—์„œ ์†Œํ”„ํŠธ์›จ์–ด ๋™์ž‘์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค

: ๋ธ”๋ž™๋ฐ•์Šค ํ…Œ์ŠคํŠธ

๐Ÿ“– Dummy

๋”-๋ฏธ ๋Š” ํ…Œ์ŠคํŠธ๋”๋ธ”์˜ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜๋กœ, ์‹ค์ œ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š”

์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ , ์˜ค์ง ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์š”๊ตฌ๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฑ„์šฐ๊ธฐ

์œ„ํ•จ์„ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค

: ๋”-๋ฏธ (๊ฐ€์งœ)

๐Ÿ“– Fake

ํ›ผ์ดํฌ๋Š” ํ…Œ์ŠคํŠธ ๋”๋ธ”๋กœ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์งœ ๊ตฌํ˜„์„

์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ธ-๋ฉ”๋ชจ๋ฆฌ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์ถ•์„ ํ•˜๋Š”๊ฒƒ

๋˜ํ•œ ํŽ˜์ดํฌ์˜ ์ผ์ข…์ž…๋‹ˆ๋‹ค

: ํ›ผ์ดํฌ

๐Ÿ“– Fixture

ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „ ์„ธํŒ…๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๋Š” ํŠน์ • ํ™˜๊ฒฝ

์ผ๋ฐ˜์ ์œผ๋กœ ํ…Œ์ŠคํŠธ์— ์‚ฌ์šฉ๋  ํ…Œ์ŠคํŠธ ๋”๋ธ”์„ ๋ฏธ๋ฆฌ ๊ตฌ์„ฑํ•œ๋‹ค

: ํ”ฝ์Šค์ณ

๐Ÿ“– Functional Testing

๊ณ ์ฐจ์›์˜ ํ…Œ์ŠคํŠธ๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค

๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ๋Š” ๋ณดํ†ต ์œ ์ € ์Šคํ† ๋ฆฌ(๋’ค์— ๋‚˜์˜ด)์„ ํฌํ•จํ•˜์—ฌ ๊ฐ€๋Šฅํ•œ

๋งŽ์€ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํฌํ•จํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ•ฉ๋‹ˆ๋‹ค

: ํ•จ์ˆ˜ํ˜•ย ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ

# In this example we check that the about page of the website is working as expected
open 'example.com'
clickOn 'about us'
assertThereIs 'We are a small Example company'

๐Ÿ“– Green

ํ†ต๊ณผํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ชจ์Œ ๋˜๋Š” ํŠน์ • ํ†ต๊ณผํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ผ์ปซ๋Š” ๋ง

:ย ๊ทธ-๋ฆฐ

๐Ÿ“– Integration Testing

Functional Testing > Integration Testing > Unit Testing

์ค‘๊ฐ„ ๋‹จ๊ณ„์˜ ํ…Œ์ŠคํŠธ ํ™œ๋™์œผ๋กœ ์—ฌ๋Ÿฌ ํ•˜์œ„ ๋ชจ๋“ˆ ๋˜๋Š” ์‹œ์Šคํ…œ์ด

์œ ๊ธฐ์ ์œผ๋กœ ๋™์ž‘ ํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ž…๋‹ˆ๋‹ค.

ย 

๋ชจ๋“ˆ/์‹œ์Šคํ…œ ๊ฐ„ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋ฐ์ดํ„ฐ ํ๋ฆ„์— ์ดˆ์ ์„ ๋งž์ถ”๋Š” ํ…Œ์ŠคํŠธ

: ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

# In this example we check that the newly registered user,
# who was referred by another user, gets an on-site "friendship" created.
# Here we check the interaction between the form controller,
# database, and a User active record
db = new Fake Db
u1 = db.createUser(name='john')
RegistrationForm(db, name='kate', referred='john').save()
assert(u1.hasFriend('kate'))

๐Ÿ“– Mock

ํ…Œ์ŠคํŠธ ๋”๋ธ”(๋’ค์— ๋‚˜์™€์—ฌ;) ํƒ€์ž… ์ค‘ ํ•˜๋‚˜๋กœ ํŠน์ •ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด

์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์•„๊นŒ ๋‚˜์™”๋˜ ํ–‰์œ„ ๊ฒ€์ฆ์„ ์œ„ํ•ด Mock ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ๋จ

: ๋ชจ-ํฌ (๋ชฉ)

public class EmailServiceMock extends EmailSevice {
    private boolean isSendMailCalled = false;
    private String message = "";
    
    @Override
    public void sendMail(String message) {
        isSendMailCalled = true;
        message = message;
    }
    
    public boolean isSendMailCalled() {
        return isSendMailCalled
    }
    
    public String getMessage() {
        return message;
    }
}

public class EmailTest {
    
    @Test
    public void testSendEmail() throws Exception {
        final String message = "์ด-๋ฉ”์ผ ๋‚ด์šฉ";
        
        // Given: Create Mock Email Service
        EmailServiceMock emailServiceMock = new EmailServiceMock();
        EmailSender emailSender = new EmailSender(emailServiceMock);
        
        // When: Send E-mail
        emailSender.send(message);
        
        // Then - sendEmail is called with our message
        Assert.assertTrue(emailServiceMock.isSendMailCalled());
        Assert.assertEquals(message, emailServiceMock.getMessage());
    }
}

๐Ÿ“– Monkey-Patching

๊ธฐ์กด ๊ฐ์ฒด ๋˜๋Š” ํด๋ž˜์Šค์˜ ๋™์ž‘์„ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค

๋ชฝํ‚คํŒจ์นญ์€ Dependency Injection ๊ณผ ํ…Œ์ŠคํŠธ ๋”๋ธ”์˜ ๋Œ€์•ˆ์ž…๋‹ˆ๋‹ค

: ๋ชฝํ‚คํŒจ์นญ

# In this example we replace the standard library function
# to prevent the test from using a real filesystem
import sys

sys.path = ["foo", "bar"]
assertContains("bar", sys.path)

๐Ÿ“– Red

์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ง‘ํ•ฉ ๋˜๋Š” ํŠน์ • ํ…Œ์ŠคํŠธ๋ฅผ ์ง€์นญ ํ•จ

: ๐Ÿšจ ๋ ˆ-๋“œ

๐Ÿ“– Refactoring

๋ฆฌํŒฉํ† ๋ง์€ ๋” ๋‚˜์€ ๊ตฌํ˜„์„ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค

"์™ธ๋ถ€ ๋™์ž‘์„ ๋ฐ”๊พธ์ง€ ์•Š์œผ๋ฉด์„œ ๋‚ด๋ถ€ ๋™์ž‘์„ ๊ฐœ์„ " ํ•˜๋Š” ๊ฒƒ์ด

๊ฐ€์žฅ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค

ย 

(๊ทผ๋ฐ ์–ด์ฐจํ”ผ ์•ˆ ํ•˜์ž–์•„? ์•ˆ๋ ๊ฑฐ์•ผ ์•„๋งˆ...)

: ๋ฆฌํŒฉํ† ๋ง (a.k.a. ๋ง๋งŒ ํ•˜๋Š” ๊ฑฐ)

๐Ÿ“– Regression

์–ด๋–ค ํ”„๋กœ๊ทธ๋žจ์ด ์ˆ˜์ •๋œ ๋’ค์— ํ•ด๋‹น ํ”„๋กœ๊ทธ๋žจ์ด ์ œ๋Œ€๋กœ ๋™์ž‘

ํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค

ย 

๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ ์ˆ˜์ • ํ›„ ๊ณผ๊ฑฐ์— ์ˆ˜์ •ํ•œ ๋ฒ„๊ทธ๊ฐ€ ๋‹ค์‹œ ์‚ด์•„๋‚˜๋Š”

"ํšŒ๊ท€ ๋ฒ„๊ทธ" ๋ฅผ ์ฐพ์•„ ๋™์ž‘์„ ๋ณด์žฅํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋˜ํ•œ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค

: ํšŒ๊ท€ ํ…Œ์ŠคํŠธ

๐Ÿ“– Setup

Fixture (ํ”ฝ์Šค์ณ) ๋ฅผ ์ค€๋น„ํ•˜๋Š” ๊ณผ์ •์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค

: ์…‹-์—…

# In this example we prepare a fake database with some fake values
# that we will need across multiple tests
db = new Fake Db
db.createUser(name='john')
db.createUser(name='kate')
db.createFriendship('john', 'kate')

๐Ÿ“– Stub

ํ…Œ์ŠคํŠธ ๋”๋ธ” ์ค‘ ํ•˜๋‚˜๋กœ, stub ์„ ํ˜ธ์ถœํ•œ ์ชฝ์— canned answer

๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. canned answer ์‚ฌ์ „์— ์•ฝ์†๋œ ๊ฐ’์„ ์˜๋ฏธ

ย 

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฉด์ ‘ ์งˆ๋ฌธ์„ ๋ฏธ๋ฆฌ ์•Œ๋ ค์ฃผ๊ณ  ๋‹ต์„ ํ•˜๋Š” ๊ฒƒ๋„

์ผ์ข…์˜ canned answer ๋ผ ํ•  ์ˆ˜ ์žˆ์Œ

(์ถœ์ฒ˜ - https://bit.ly/2Nedp4Q)

: ์Šคํ…

 (function () {
 	console.log(โ€œ== ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค โ€” ๊ฒฐ์ œ๊ฐ€ ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐโ€);
 	
 // Given
 // Sinon ์„ ์‚ฌ์šฉํ•˜์—ฌ Stub ์ฒ˜๋ฆฌ
 var stub = sinon.stub(PaymentGateway.prototype, โ€˜requestPaymentโ€™);
 // canned answer
 stub.withArgs(โ€˜ํ…Œ์ŠคํŠธ ์ƒํ’ˆโ€™, 2000).returns(โ€˜OKโ€™);
 
 // When
 var order = new Order(โ€˜ํ…Œ์ŠคํŠธ ์ƒํ’ˆโ€™, 2000);
 var result = order.pay();
 
 // Then
 if(result == true) {
 	console.log(โ€œ> ํ…Œ์ŠคํŠธ ์„ฑ๊ณตโ€);
 } else {
 	console.log(โ€œ> ํ…Œ์ŠคํŠธ ์‹คํŒจโ€);
 }
 
 stub.restore();
})();

(function () { 
	console.log(โ€œ== ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค โ€” ๊ฒฐ์ œ๊ฐ€ ์‹คํŒจํ•œ ๊ฒฝ์šฐโ€);
	
 // Given
 // Sinon ์„ ์‚ฌ์šฉํ•˜์—ฌ Stub ์ฒ˜๋ฆฌ
 var stub = sinon.stub(PaymentGateway.prototype, โ€˜requestPaymentโ€™);
 // canned answer
 stub.withArgs(โ€˜ํ…Œ์ŠคํŠธ ์ƒํ’ˆโ€™, 0).returns(โ€˜ERRORโ€™);
 
 // When
 var order = new Order(โ€˜ํ…Œ์ŠคํŠธ ์ƒํ’ˆโ€™, 0);
 var result = order.pay();
 
 // Then
 if(result == false) {
 	console.log(โ€œ> ํ…Œ์ŠคํŠธ ์„ฑ๊ณตโ€);
 } else {
 	console.log(โ€œ> ํ…Œ์ŠคํŠธ ์‹คํŒจโ€);
 }
 
 stub.restore();
})();

๐Ÿ“– Teardown

Setup ์—์„œ ๋งŒ๋“  ํ”ฝ์Šค์ณ๋ฅผ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค

GC ๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์–ธ์–ด์˜ ๋Œ€๋ถ€๋ถ„์€ Teardown ์„

์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค

: ํ‹ฐ-์–ด ๋‹ค์šด (๋ถ„ํ•ด, ํ•ด์ฒด)

๐Ÿ“– Test

์š”๊ตฌ์‚ฌํ•ญ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„

: ํ…Œ์ŠคํŠธ (ํ…Œ์ŠคํŠธ์ผ€์ด์Šค์™€ ๋‹ค๋ฅด๋‹ค)

๐Ÿ“– Test Case

ํ…Œ์ŠคํŠธ์˜ ์ง‘ํ•ฉ

: ํ…Œ์ŠคํŠธ์ผ€์ด์Šค

๐Ÿ“– Test Coverage

ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์ •๋Ÿ‰์ ์ธ ์ˆ˜์น˜๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ

์†Œ์Šค ์ฝ”๋“œ (ํ…Œ์ŠคํŠธ ๋Œ€์ƒ: SUT) ์ค‘ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์‹คํ–‰๋œ ์ฝ”๋“œ

๋น„์œจ์„ ๋œปํ•ฉ๋‹ˆ๋‹ค

ย 

๊ตฌ๋ฌธ, ์กฐ๊ฑด, ๊ฒฐ์ • ๋ชจ๋‘๋ฅผ ํ…Œ์ŠคํŠธ ํ•ด์•ผ 100%๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค

: ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€

๐Ÿ“– Test Cycle

TDD ์˜ ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ๋ ˆ๋“œ - ๊ทธ๋ฆฐ - ๋ฆฌํŒฉํ„ฐ ๊ณผ์ •์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค

: ํ…Œ์ŠคํŠธ ์ˆœํ™˜

๐Ÿ“– Test Double

ํ…Œ์ŠคํŠธ๋Š” ๋…๋ฆฝ์„ฑ์„ ์œ ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ์ˆœ์„œ ๋˜๋Š”

๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ๋˜๋Š”๋ฐ, ์ด์™€ ๊ฐ™์€ ์ƒํ™ฉ์„ ์œ„ํ•ด

์˜์กด์„ฑ์œผ๋กœ ๋ถ€ํ„ฐ ๊ฒฉ๋ฆฌ ์‹œํ‚ค๊ณ , ์˜์กด์„ฑ์„ ๋Œ€์ฒด ํ•˜๋Š” ๊ฒƒ์„

์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ย 

Stub/Mock/Fake/Dummy/Spy ๋“ฑ์ด ํ…Œ์ŠคํŠธ ๋”๋ธ”์ž…๋‹ˆ๋‹ค

(๋”๋ธ”์€ "๋Œ€์—ญ" ์ด๋ผ๋Š” ๋œป์ด ์žˆ์Šต๋‹ˆ๋‹ค)

: ํ…Œ์ŠคํŠธ ๋”๋ธ” (๋“œ๋””์–ด ๋‚˜์˜ด)

๐Ÿ“– Test Suite

Testcase ์˜ ์ง‘ํ•ฉ

: ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ

๐Ÿ“– Unit Testing

๊ฐ€์žฅ ๋‚ฎ์€ ๋‹จ๊ณ„์˜ ํ…Œ์ŠคํŠธ๋กœ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์˜

์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ํ•˜๋‚˜์˜ ํ–‰์œ„๋งŒ์„

๊ฒ€์ฆํ•˜๊ณ , ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค(Unit test case) ๋Š” ํ•จ์ˆ˜ ๋˜๋Š”

ํด๋ž˜์Šค์˜ ๋ชจ๋“  functionality ๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค

: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

๐Ÿ“– User Story

ํŠน์ •ํ•œ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํŠน์ •ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š”

ํŠน์ •ํ•œ ๊ทธ๋ฃน์˜ ์‚ฌ๋žŒ๋“ค์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค

ย 

์œ ์ € ์Šคํ† ๋ฆฌ๋Š” ์ƒ์„ธ ๊ตฌํ˜„์— ๋Œ€ํ•œ ์„ค๋ช…์„ ํ”ผํ•˜๊ณ 

์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ์ˆ ์  ๋‚ด์šฉ์„ ๋ฐฐ์ œํ•œ (๊ธฐ์ˆ ์ ์ด๋ฉด ์‚ฌ๋žŒ์€ ๋ชป ์ฝ๋Š”๊ฑด๊ฐ€...?)

๊ฐ„๋‹จํ•œ ๋ช‡ ๊ฐ€์ง€ ๋‹จ์–ด๋ฅผ ์‚ฌ์šฉํ•ด ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค

: ์œ ์ €(์•…๋งˆ) ์Šคํ† ๋ฆฌ

As a user, I want to be able to find my friends on this website by my address book, instead of looking for them one by one, because that will save me a lot of time.

๐Ÿ“– White-Box Testing

์„ค๊ณ„ ๋‹จ๊ณ„์—์„œ ์š”๊ตฌ๋œ ์‚ฌํ•ญ์„ ์ด๋ฏธ ์•„๋Š” ์ƒํƒœ๋กœ ๊ฐœ๋ฐœ์ž ๊ด€์ 

์—์„œ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŒ… ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ปค๋ฒ„๋ฆฌ์ง€ ๋˜ํ•œ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค

ย 

๊ฒ€์ฆ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋ฌธ์žฅ/์„ ํƒ/๊ฒฝ๋กœ/์กฐ๊ฑด ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค

: ํ™”์ดํŠธ ๋ฐ•์Šค ํ…Œ์ŠคํŒ…

~ TDD ํ›ˆ๋ จ๋ฒ• ~

ย 

๋งค๋ฅผ ๋งž์•„๋ด์•ผ ์•„ํ”ˆ๊ฑธ ์•ˆ๋‹ค

ํ…Œ์ŠคํŠธ๊ฐ€ ์ฃผ๋Š” ์•ˆ์ •๊ฐ์ด ์žˆ์Šต๋‹ˆ๋‹ค

๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์•ผ ๊ณ ์žฅ๋‚˜๋ฉด ๊ณ ์น˜๋ฉด ๋˜์ง€๋งŒ

๋‹น์žฅ ๋‚ด ์‹ค์ˆ˜๋กœ ๋ช‡ ์ฒœ๋งŒ์›์ด ์˜ค๊ฐ„๋‹ค๋ฉด? ํ…Œ์ŠคํŠธ ์—†์ด๋Š” ๋ผ์ด๋ธŒ ๋ฐฐํฌ๋„ ์—†๋‹ค ๐Ÿ˜ญ

ํ•„์š”์„ฑ์„ ๋Š๋ผ์…จ๋‹ค๋ฉด, ๋Š์ž„์—†๋Š” ๋ฐ˜๋ณต ํ›ˆ๋ จ์œผ๋กœ ํ…Œ์ŠคํŒ… ๊ณ ํŠธ๋‹˜๊ป˜ ๋ณต์ข…ํ•ฉ์‹œ๋‹ค

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

A long time ago...

ย 

์™€์ด์บ์‹œ๋ผ๋Š” ์ฑ„๊ถŒ ํฌํŠธํด๋ฆฌ์˜ค ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ๋งŒ๋“œ๋Š” ํšŒ์‚ฌ๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ...
๊ณ ๊ฐ(์•…๋งˆ)์ด ์™€์„œ ๋‹ค๋ฅธ ํ™”ํ๋Š” ์™œ ์•ˆ๋˜๋ƒ... ์‚ฌ์žฅ๋‹˜(์•…๋งˆ)์€ ํ•  ์ˆ˜ ์žˆ์ง€? ๋ผ๊ณ  ํ•˜๊ณ ์žˆ๊ณ 
๊ทธ๋ž˜์„œ 6๊ฐœ์›” ๋™์•ˆ (์ข‹์€ ํšŒ์‚ฌ) ๋ญ ์–ด์ฉŒ๊ตฌ ์ €์ฉŒ๊ตฌ ํ•ด์„œ ์ฑ…์ž„ ๋ถ„๋ฆฌํ•˜๊ณ  ํ•ด์„œ ์™„์„ฑํ•˜๋‹ˆ๊นŒ
ํšŒ์‚ฌ๊ฐ€์น˜๊ฐ€ ๋ช‡ ๊ณฑ์ ˆ ์˜ฌ๋ž๋‹ค๋Š” ์ „์„ค๊ฐ™์€ ์ด์•ผ๊ธฐ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

TDD ์—๋„ ๋ฆฌ๋“ฌ์ด ์žˆ๋‹ค๋Š”๋ฐ...?

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

ํ˜•... ๊ทธ๋ƒฅ ๊ณต ์ฐจ๋ฉด ์•ˆ๋ผ์š”?

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

1. (์žฌ๋นจ๋ฆฌ) ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•œ๋‹ค

2. ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด ์‹คํŒจํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค

3. ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ๋ฐ”๊พผ๋‹ค

4. ๋‹ค์‹œ ํ…Œ์ŠคํŠธ ๋Œ๋ฆฐ๋‹ค

5. ๋ฆฌํŒฉํ† ๋ง

TDD์˜ ๋ฆฌ๋“ฌ (Cycle)

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๋‚˜๋Š” ๋†€๋ผ๊ฒŒ ๋œ๋‹ค (?)

  • ๊ฐ๊ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ธฐ๋Šฅ์˜ ์ž‘์€ ์ฆ๊ฐ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ์ปค๋ฒ„ํ•˜๋Š”์ง€
  • ์ƒˆ ํ…Œ์ŠคํŠธ๋ฅผ ๋Œ์•„๊ฐ€๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์–ผ๋งˆ๋‚˜ ์ž‘๊ณ  ๋ชป์ƒ๊ธด ๋ณ€ํ™”๊ฐ€ ๊ฐ€๋Šฅํ•œ์ง€
  • ์–ผ๋งˆ๋‚˜ ์ž์ฃผ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š”์ง€
  • ์–ผ๋งˆ๋‚˜ ์ˆ˜ ์—†์ด ์ž‘์€ ๋‹จ๊ณ„๋ฅผ ํ†ตํ•ด ๋ฆฌํŒฉํ† ๋ง์ด ๋˜์–ด๊ฐ€๋Š”์ง€

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์š”๊ตฌ์‚ฌํ•ญ์€ ๋ฌด์—‡์ธ๊ฐ€ (Before)

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์š”๊ตฌ์‚ฌํ•ญ์€ ๋ฌด์—‡์ธ๊ฐ€ (After)

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๊ธฐ๋Šฅ์„ ์™„์„ฑํ•˜๋ ค๋ฉด...

1. ํ†ตํ™”๊ฐ€ ๋‹ค๋ฅธ ๋‘ ๊ธˆ์•ก์„ ๋”ํ•ด ํ™˜์œจ์— ๋งž๊ฒŒ ๊ธˆ์•ก์„ ํ‘œ์‹œ

2. ์–ด๋–ค ๊ธˆ์•ก(์ฃผ๊ฐ€)์„ ์–ด๋–ค ์ˆ˜(์ฃผ์‹ ์ˆ˜)์— ๊ณฑํ•œ ๊ธˆ์•ก์„ ํ‘œ์‹œ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๊ธฐ๋Šฅ์„ ์™„์„ฑํ•˜๋ ค๋ฉด...

1. ํ†ตํ™”๊ฐ€ ๋‹ค๋ฅธ ๋‘ ๊ธˆ์•ก์„ ๋”ํ•ด ํ™˜์œจ์— ๋งž๊ฒŒ ๊ธˆ์•ก์„ ํ‘œ์‹œ (์–ด๋ ค์›€)

2. ์–ด๋–ค ๊ธˆ์•ก(์ฃผ๊ฐ€)์„ ์–ด๋–ค ์ˆ˜(์ฃผ์‹ ์ˆ˜)์— ๊ณฑํ•œ ๊ธˆ์•ก์„ ํ‘œ์‹œ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์ฝ”๋”ฉ๋ถ€ํ„ฐ ๋…ธ๋†‰ ํ…Œ์ŠคํŠธ ๋ถ€ํ„ฐ

๋จผ์ € ์ด๋ ‡๊ฒŒ ๋™์ž‘ํ•˜๋ฉด (Operation) ์ข‹๊ฒ ๋‹ค ๋ถ€ํ„ฐ ์ƒ์ƒํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค

public void testMultiplication() {
  Dollar five = new Dollar(5);
  five.times(2);
  assertEquals(10, five.amount);
}

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์ž ๊น, Assertion ์ž‘์„ฑ ๋ฐฉ๋ฒ•

JUnit ์—์„œ๋Š” (expected, actual) ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค

void assertEquals(Object expected, Object actual);

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์ด ์ฝ”๋“œ๋Š” ๋ฌด์—‡์ด ๋ฌธ์ œ์ธ๊ฐ€

public void testMultiplication() {
  Dollar five = new Dollar(5);
  five.times(2);
  assertEquals(10, five.amount);
}

1. ๊ณต์šฉ ํ•„๋“œ ์‚ฌ์šฉ

2. Side Effect

3. Int value

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๋ฌธ์ œ๋ฅผ ์ƒ๊ฐํ•ด ๋‚ด๋Š” ๊ฒƒ๋„ ์žฌ๋Šฅ์ž„...

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์ด์ œ Todo๋ฅผ ์™ผ์ชฝ์— ์ ์–ด ๋‘˜๊ฒŒ์š”

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

์ด ์ฝ”๋“œ๋Š” ์‹คํ–‰์ด ์•ˆ๋œ๋‹ค

public void testMultiplication() {
  Dollar five = new Dollar(5);
  five.times(2);
  assertEquals(10, five.amount);
}
  • Dollar ํด๋ž˜์Šค ์—†์Œ
  • ์ƒ์„ฑ์ž ์—†์Œ
  • times(int amount) ๋ฉ”์„œ๋“œ ์—†์Œ
  • amount ํ•„๋“œ ์—†์Œ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ (1/4)

class Dollar
  • Dollar ํด๋ž˜์Šค ์—†์Œ
  • ์ƒ์„ฑ์ž ์—†์Œ
  • times(int multiplier) ๋ฉ”์„œ๋“œ ์—†์Œ
  • amount ํ•„๋“œ ์—†์Œ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ (2/4)

class Dollar {
    Dollar(int amount) {
    
    }
}
  • Dollar ํด๋ž˜์Šค ์—†์Œ
  • ์ƒ์„ฑ์ž ์—†์Œ
  • times(int multiplier) ๋ฉ”์„œ๋“œ ์—†์Œ
  • amount ํ•„๋“œ ์—†์Œ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ (3/4)

class Dollar {
    Dollar(int amount) {
    
    }
    
    void times(int multiplier) {
    
    }
}
  • Dollar ํด๋ž˜์Šค ์—†์Œ
  • ์ƒ์„ฑ์ž ์—†์Œ
  • times(int multiplier) ๋ฉ”์„œ๋“œ ์—†์Œ
  • amount ํ•„๋“œ ์—†์Œ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ (4/4)

class Dollar {

    int amount;
    
    Dollar(int amount) {
    
    }
    
    void times(int multiplier) {
    
    }
}
  • Dollar ํด๋ž˜์Šค ์—†์Œ
  • ์ƒ์„ฑ์ž ์—†์Œ
  • times(int multiplier) ๋ฉ”์„œ๋“œ ์—†์Œ
  • amount ํ•„๋“œ ์—†์Œ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ํ…Œ์ŠคํŠธ๊ฐ€ ์ด์ œ ์‹คํŒจํ•œ๋‹ค

class Dollar {

    int amount = 10;
    
    Dollar(int amount) {
    
    }
    
    void times(int multiplier) {
    
    }
}
  • Dollar.amount ๊ฐ€ 10์ด๋ฉด ๋จ

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

$5 * 2 = $10

class Dollar {

    int amount;
    
    Dollar(int amount) {
    
    }
    
    void times(int multiplier) {
        amount = 5 * 2
    }
}
  • ์ž‘์€ ๋‹จ๊ณ„๋ฅผ ๋ฐŸ์•„ ๋‚˜๊ฐ€๋ฉด์„œ ๋ฆฌํŒฉํ† ๋ง์„ ํ•˜์ž
  • ๊ทผ๋ฐ ๋‚ด๊ฐ€ ์ด๋ ‡๊ฒŒ ํ•˜๋Š๋ƒ? ์•„๋‹ˆ...
  • ํ•˜์ง€๋งŒ ์—ฐ์Šต์€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

$5 * 2 = $10

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    void times(int multiplier) {
        amount *= multiplier
    }
}
  • ์ž‘์€ ๋‹จ๊ณ„๋ฅผ ๋ฐŸ์•„ ๋‚˜๊ฐ€๋ฉด์„œ ๋ฆฌํŒฉํ† ๋ง์„ ํ•˜์ž
  • ๊ทผ๋ฐ ๋‚ด๊ฐ€ ์ด๋ ‡๊ฒŒ ํ•˜๋Š๋ƒ? ์•„๋‹ˆ...
  • ํ•˜์ง€๋งŒ ์—ฐ์Šต์€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค

ย  ย  ย  ๐Ÿงช ๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋Š” Money ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

Wrapping up

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    void times(int multiplier) {
        amount *= multiplier
    }
}
  • ํ…Œ์ŠคํŠธ ๋ชฉ๋ก ์ž‘์„ฑ
  • ์˜คํผ๋ ˆ์ด์…˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ฝ”๋“œ๋กœ ํ‘œํ˜„
  • Todo list ์ž‘์„ฑ
  • ์Šคํ… ๊ตฌํ˜„
  • ํ…Œ์ŠคํŠธ ํ†ต๊ณผ
  • ๋ฆฌํŒฉํ† ๋ง

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋ชฉ์ 

๋™์ž‘ํ•˜๋Š” ๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

๋™์ž‘์„ ์‹œํ‚ค๊ณ  ๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์ž?

๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ๋™์ž‘์„ ํ•˜๋„๋ก ํ•˜์ž?

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

๋™์ž‘์„ ์‹œํ‚ค๊ณ  ๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์ž

๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ๋™์ž‘์„ ํ•˜๋„๋ก ํ•˜์ž?

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

Dollar Side Effect

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    void times(int multiplier) {
        amount *= multiplier
    }
}

์ง€๊ธˆ ์ฝ”๋“œ๋Œ€๋กœ๋ผ๋ฉด Dollar ๊ฐ์ฒด์˜ ๊ฐ’์ด ์—ฐ์‚ฐํ•˜๊ณ  ๋‚˜๋ฉด ๋ฐ”๋€๋‹ค

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

์›ํ•˜๋Š” ํ˜•ํƒœ๋ฅผ ํ…Œ์ŠคํŠธ๋กœ ์ž‘์„ฑํ•œ๋‹ค

public void testMultiplication() {
    Dollar five = new Dollar(5);
    Dollar product = five.times(2);
    assertEquals(10, product.amount);
	product = five.times(3);
    assertEquals(15, product.amount);
}
.times() ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ƒˆ Dollar ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•œ๋‹ค

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    Dollar times(int multiplier) {
        return new Dollar(amount * multiplier)
    }
}
.times() ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ƒˆ Dollar ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•œ๋‹ค

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ์ดˆ๋ก ๋ง‰๋Œ€๋ฅผ ๋ณด๋Š” ๋ฐฉ๋ฒ•

ย 

1. ๊ฐ€์งœ๋กœ(stub) ๊ตฌํ˜„ํ•˜๊ธฐ: ์ƒ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š” ๊ฐ’ (canned answer) ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•œ๋‹ค

2. ๊ฐ€์งœ ๊ตฌํ˜„์„ ์‹ค์ œ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    Dollar times(int multiplier) {
        return new Dollar(amount * multiplier)
    }
}
.times() ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ƒˆ Dollar ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•œ๋‹ค

ย  ย  ย  ๐Ÿงช ํƒ€๋ฝํ•œ ๊ฐ์ฒด

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

์–ด๋–ค ์ •์ˆ˜์— 1์„ ๋”ํ–ˆ์„ ๋•Œ ์›๋ž˜ ์ •์ˆ˜๊ฐ€ ๋ณ€ํ•˜๊ธฐ ๋ณด๋‹ค

1์ด ๋”ํ•ด์ง„ ์ƒˆ๋กœ์šด ์ •์ˆ˜๋ฅผ ๊ฐ–๊ธธ ์›ํ•œ๋‹ค

ย 

์‚ฌ๋”ธ๋ผ์— 1๋”ธ๋ผ๋ฅผ ๋”ํ•˜๋ฉด, ์ƒˆ๋กœ์šด ์˜ค๋”ธ๋ผ ๊ฐ์ฒด๊ฐ€ ๋‚˜์˜ค๊ธธ ๊ธฐ๋Œ€ํ•œ๋‹ค

ย 

์ด๋Ÿฐ ๊ฒƒ์„ ๊ฐ’ ๊ฐ์ฒด ํŒจํ„ด(Value object parttern) ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

VO Pattern ์„ ์‚ฌ์šฉํ•˜๋ฉด

๊ธฐ์กด ๊ฐ’์„ ๋ณ€ํ™”์‹œํ‚ค๋Š” ๊ฑฑ์ •์€ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค

ย 

๋‹ค๋งŒ, ๊ฐ’ ๊ฐ์ฒด์˜ ๋น„๊ต๋ฅผ ์œ„ํ•ด .equals() ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

๋˜ํ•œ, ๊ฐ’ ๊ฐ์ฒด๋ฅผ HashMap ์˜ ํ‚ค๋กœ ์“ฐ๊ธฐ ์œ„ํ•ด .hashcode() ๋„ ๊ตฌํ˜„

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

.equals()

.hashcode()

ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ๋งŒ๋“ค์ž

public void testEquality() {
    assertTrue(new Dollar(5).equals(new Dollar(5)));
}
.equals()

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

ย ๋ฅผ ๊ตฌํ˜„ํ•ด, Dollar ๊ฐ์ฒด๊ฐ„ ๋น„๊ต๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์ž

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

.equals()

.hashcode()

์ผ๋‹จ์€ stub ๊ตฌํ˜„์œผ๋กœ ํ†ต๊ณผ์‹œํ‚ค์ž

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    Dollar times(int multiplier) {
        return new Dollar(amount * multiplier)
    }
    
    public boolean equals(Object object) {
        return true;
    }
}

assertTrue ๋ฅผ ๋งŒ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด true ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

์‚ผ๊ฐ์ธก๋Ÿ‰ ์ „๋žต

ย 

2๊ฐœ ์ด์ƒ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ด ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ถ”์ƒํ™”๋ฅผ ๋„์ถœํ•ด ๋‚ธ๋‹ค

assertEqual(multiply(3, 3), sum(3, 3, 3))

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

.equals()

.hashcode()

์‚ผ๊ฐ์ธก๋Ÿ‰์„ ์œ„ํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ž

public void testEquality() {
    assertTrue(new Dollar(5).equals(new Dollar(5)));
    assertFalse(new Dollar(5).equals(new Dollar(6)));
}

์•„ํ•˜, ๊ฐ€๋งŒ ๋ณด๋‹ˆ true/false boolean ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ๊ฒ ๊ตฌ๋‚˜

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

.equals()

.hashcode()

๋™์น˜์„ฑ์„ ์ผ๋ฐ˜ํ™”(์ถ”์ƒํ™”) ํ•˜๋Š” ๊ตฌํ˜„์„ ๋งŒ๋“ ๋‹ค

class Dollar {

    int amount;
    
    Dollar(int amount) {
        this.amount = amount;
    }
    
    Dollar times(int multiplier) {
        return new Dollar(amount * multiplier)
    }
    
    public boolean equals(Object object) {
        Dollar dollar = (Dollar) object;
        return amount == dollar.amount;
    }
}

๋น„๊ต์— ๋Œ€ํ•œ ์ถ”์ƒํ™”๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„์„ ์™„์„ฑํ–ˆ๋‹ค

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

.equals()

.hashcode()

Equal null

Equal object

ํ•˜์ง€๋งŒ, null ๋˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์™€์˜ ๋น„๊ต๋Š”?

์ผ๋‹จ์€ ํ•  ์ผ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•ด ๋‘”๋‹ค

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

๐Ÿฐ Todo List

ย 

$5 + 10CHF = $10

$5 * 2 = $10

private amount

Dollar Side Effect

Money ๋ฐ˜์˜ฌ๋ฆผ

์ฝ”๋“œ๊ฐ€ ์•ˆ ๋Œ์•„๊ฐ

.equals()

.hashcode()

Equal null

Equal object

Wrapping up

  • ์šฐ๋ฆฌ์˜ ๋””์ž์ธ ํŒจํ„ด(๊ฐ’ ๊ฐ์ฒด)์ด ํ•˜๋‚˜์˜ ๋˜ ๋‹ค๋ฅธ ์˜คํผ๋ ˆ์ด์…˜(equals) ๋ฅผ ์•”์‹œํ•œ๋‹ค

  • ์˜คํผ๋ ˆ์ด์…˜์„ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค

  • ์˜คํผ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„์„ ํ–ˆ๋‹ค

  • ๋ฐ”๋กœ ๋ฆฌํŒฉํ† ๋ง ํ•˜์ง€ ์•Š๊ณ , ์‚ผ๊ฐ์ธก๋Ÿ‰์„ ํ†ตํ•ด ๊ตฌํ˜„์„ ๊ตฌ์ฒดํ™” ํ–ˆ๋‹ค

  • ๊ตฌ์ฒดํ™” ๋œ ๊ตฌํ˜„์„ ํ†ตํ•ด ๋ฆฌํŒฉํ† ๋ง์„ ์ˆ˜ํ–‰ํ–ˆ๋‹ค

ย  ย  ย  ๐Ÿงช ๋ชจ๋‘๋ฅผ ์œ„ํ•œ ํ‰๋“ฑ

Summary

๐ŸŽน ๋ฆฌ๋“ฌ์— ๋ชธ์„ ๋งก๊ธฐ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•œ๋‹ค

๐ŸŒผ ์ข‹๊ณ  ์•„๋ฆ„๋‹ค์šด ๊ตฌํ˜„์€ ๋‚˜์ค‘์— ์ƒ๊ฐํ•œ๋‹ค

๐Ÿ‘ ํ…Œ์ŠคํŠธ์— ๋ณต์ข…ํ•ด๋ผ, ์ด๊ฑธ ์™œ ํ•˜๋Š”์ง€ ์˜์‹ฌํ•˜์ง€ ๋งˆ๋ผ

ย 

ํ˜น์‹œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ณด๊ณ  ์„ค๊ณ„๋ถ€ํ„ฐ ๋– ์˜ฌ๋ ธ์œผ๋ฉด ๋งด๋งค๋ฅผ ๋งž์ž

Test driven Development

By Doon Doon

Test driven Development

Test Driven Development - Kent beck. Chapter 1 ~ 3

  • 101
Loading comments...

More from Doon Doon