JiwonDev

๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ์™€ Test Double (+Mockist)

by JiwonDev

Mockito ๋ ˆํผ๋Ÿฐ์Šค https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html

 

Mockito - mockito-core 3.12.4 javadoc

Latest version of org.mockito:mockito-core https://javadoc.io/doc/org.mockito/mockito-core Current version 3.12.4 https://javadoc.io/doc/org.mockito/mockito-core/3.12.4 package-list path (used for javadoc generation -link option) https://javadoc.io/doc/org

javadoc.io

# Test Double์˜ ์ข…๋ฅ˜

Test Double์ด๋ž€ ์˜ํ™” ์ดฌ์˜์‹œ ์œ„ํ—˜ํ•œ ์—ญํ• ์„ ๋Œ€์‹ ํ•˜๋Š” ์Šคํ„ดํŠธ-๋”๋ธ” ๋ฐฐ์šฐ๋“ค์ฒ˜๋Ÿผ ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ๋Œ€์‹ ํ•˜๋Š” ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ํ…Œ์ŠคํŒ…์— ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์˜๋ฏธํ•œ๋‹ค. ํ…Œ์ŠคํŠธ ๋”๋ธ”์—๋Š” Dummy, Fake, Stub, Spy, Mock์ด ์กด์žฌํ•œ๋‹ค.

 

๋ชจ๋“  Test Double์„ ๋‹จ์ˆœํžˆ 'ํ…Œ์ŠคํŠธ ๊ฐ์ฒด'๋ผ๊ณ  ๋ญ‰๋šฑ๊ทธ๋ ค ๋งํ•ด๋„ ์ƒ๊ด€์€ ์—†์ง€๋งŒ, ๊ฐ๊ฐ์˜ ์šฉ๋„๊ฐ€ ๋‹ค๋ฅด๊ณ  ์˜์‚ฌ์†Œํ†ต์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ตฌ๋ถ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค.

 

@ Dummy Object

๊ป๋ฐ๊ธฐ๋งŒ ์žˆ๊ณ  ์•„๋ฌด๋Ÿฐ ๋™์ž‘๋„ ํ•˜์ง€์•Š๋Š” ๊ฐ์ฒด์ด๋‹ค. (ํŒŒ๋ผ๋ฉ”ํƒ€์— ์ „๋‹ฌ๋˜๋Š” ๋”๋ฏธ ๋นˆ ๊ฐ์ฒด๋“ฑ)

 

@ Fake Object

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

๋‹จ์ˆœํ™”๋œ ๋™์ž‘์„ ์ œ๊ณตํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. H2 ๊ฐ™์€ ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋„ Fake ๋ผ๊ณ  ๋ณผ ์ˆ˜์žˆ๋‹ค.

public final class FakeAccountRepository{
    private final Map<Long, Account> data = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong();

    public Account findByEmail(String email) {
        return data.values().stream()
            .filter(account -> email.equals(account.getEmail()))
            .findAny()
            .orElse(null);
    }

    public Account save(Account entity) {
        entity.setId(idGenerator.incrementAndGet());
        data.put(entity.getId(), entity);
        return entity;
    }
}

 

@ Stub Object

ํ…Œ์ŠคํŠธ์—์„œ ํ˜ธ์ถœ๋œ ์š”์ฒญ์— ๋Œ€ํ•ด ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด๋‘” ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด์ด๋‹ค.

๋™์ž‘์—ฌ๋ถ€๋Š” ์ƒ๊ด€์—†๊ณ , ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋ฏธ๋ฆฌ ์ค€๋น„๋œ ๊ฒฐ๊ณผ๋ฌผ์„ ์‘๋‹ตํ•˜๋Š” ๊ฐ์ฒด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

private final class StubAccountRepository{
    public Account save(Account account){
        return new Account("person","123");
    }
    
    public int update(Account account){
        return 1;
    }
}

 

@ Spy Object (Stub + Logging)

Stub ๊ฐ์ฒด์˜ ์—ญํ• ์„ ๊ฐ€์ง€๋ฉด์„œ ํ˜ธ์ถœ๋œ ๋‚ด์šฉ์˜ ์ •๋ณด๋ฅผ ํ…Œ์ŠคํŠธ ๋กœ๊ทธ์— ๋‚จ๊ธด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋ฉ”์ผ๋ง ์„œ๋น„์Šค์—์„œ ๋ฐœ์†ก๋œ ๋ฉ”์ผ ๊ฐœ์ˆ˜๋ฅผ ์ธก์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

@ Mock Object

ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ธฐ๋Œ€๋ฅผ ๋ฏธ๋ฆฌ ๋ช…์„ธ specification ํ•ด๋†“๊ณ , ํ•ด๋‹น ๋‚ด์šฉ์— ๋”ฐ๋ผ ๋™์ž‘ํ•˜๋„๋ก ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋œ ๊ฐ€์งœ ๊ฐ์ฒด์ด๋‹ค.

Fake, Spy์ฒ˜๋Ÿผ ์‹ค์ œ ๋™์ž‘์„ ๊ตฌํ˜„ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ Mocking ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋งŒ๋“ ๋‹ค.

 

๊ทธ๋Ÿผ Stub์ด๋ž‘ ๋น„์Šทํ•œ๊ฒŒ ์•„๋‹Œ๊ฐ€? ํ•˜๋Š” ์˜๋ฌธ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. Stub์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ง์ ‘ ํ…Œ์ŠคํŠธ์šฉ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค.

public interface MailService {
    public void send(Message msg);
}

public class MailServiceStub implements MailService {
    private List<Message> messages = new ArrayList<Message>();

    public void send(Message msg) { messages.add(msg); }

    public int numberSent() { return messages.size(); }
}

 

 

Mock์€ ํŠน์ • ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์—ˆ์„ ๋•Œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ชจํ‚น(Mocking)ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

โžก ํŠน์ • ๋™์ž‘์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘์œผ๋กœ ๊ฐ€๋กœ์ฑ„์„œ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋ฐ”๊พผ๋‹ค.

โžก Mocking์€ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๋ฟ๋งŒ์•„๋‹ˆ๋ผ ๊ฐ์ฒด์ƒ์„ฑ, ์˜ˆ์™ธ๋ฐœ์ƒ, ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์—ฌ๋ถ€(verify)๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰ Stub์€ [์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ, ์ƒํƒœ]๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ์šฉ๋„์ด๊ณ  Mock์€ [ํ–‰์œ„, ๋ฉ”์„œ๋“œ ์ž์ฒด]๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ์šฉ๋„์ด๋‹ค. 

 


# ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜

ํ”ํžˆ๋“ค ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋‹จ์œ„ํ…Œ์ŠคํŠธ, ํ†ตํ•ฉ, ๊ธฐ๋Šฅ, ์Šน์ธ ํ…Œ์ŠคํŠธ๋ผ๋Š” ์šฉ์–ด๋ฅผ ์“ด๋‹ค. ์ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

 

@ ํ•™์Šต ํ…Œ์ŠคํŠธ (learning Test)

์ด๋Š” ํ”„๋กœ์ ํŠธ ํ…Œ์ŠคํŠธ์™€๋Š” ์—ฐ๊ด€์ด ์—†๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๊ฐœ๋ฐœ์ž์˜ ํ•™์Šต, ์ดํ•ด๋ฅผ ๋•๊ธฐ์œ„ํ•œ ํ…Œ์ŠคํŠธ.

python ์ฝ˜์†”์ฐฝ์„ ์—ด์–ด  if(3) print("A") ๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€ ๋Œ๋ ค๋ณด๋Š” ๊ฒƒ๋„ ์ผ์ข…์˜ ํ•™์Šตํ…Œ์ŠคํŠธ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€์— ํ•™์Šตํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋Œ๋ ค๋ณด๊ณ  ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์ฐธ๊ณ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฌผ๋ก  ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๋„๋ก ๋นŒ๋“œ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์ž๋™ ํ…Œ์ŠคํŠธ์—์„œ ์ œ์™ธ์‹œ์ผœ๋Š” ๊ฒƒ์„ ์žŠ์ง€๋ง์ž. 

 

@ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Unit Test)

[ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์˜ ์ฝ”๋“œ]๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค. ํ•œ๊ธ€๋กœ ๋ฒˆ์—ญํ•˜๋‹ˆ ์˜๋ฏธ๊ฐ€ ์กฐ๊ธˆ ์–ด์ƒ‰ํ•˜๊ธด ํ•˜๋‹ค.

  • ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋Š” [ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š” ์ฝ”๋“œ]๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ๋‹ค๋ฅธ๊ณณ๊ณผ ์™„๋ฒฝํ•˜๊ฒŒ ๋…๋ฆฝ์ ์ด์–ด์•ผํ•œ๋‹ค.
    โžก ํšŒ์›๊ฐ€์ž… ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ…Œ์ŠคํŠธํ•œ๋‹ค๋ฉด ํšŒ์›์ด ์ž˜ ๊ฐ€์ž…๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š”๊ฑฐ์ง€, ์›น ์„œ๋ฒ„์˜ ์ •์ƒ๋™์ž‘ ์—ฌ๋ถ€๋‚˜ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๊นŒ์ง€ ์žก์„ ํ•„์š”๋Š” ์—†๋‹ค.
  • ๊ทธ๋ž˜์„œ ๋‹จ์œ„ํ…Œ์ŠคํŠธ์—์„œ๋Š” Test-Double์„ ์‚ฌ์šฉํ•ด ๋‹ค๋ฅธ ๊ณณ๊ณผ ์—ฐ๊ฒฐ์„ ๋Š์–ด ๋…๋ฆฝ์ ์œผ๋กœ ๋งŒ๋“ ๋‹ค.
    โžก ํ…Œ์ŠคํŠธ์˜ ๋Œ€์ƒ ๋ฒ”์œ„๊ฐ€ ์ž‘๊ธฐ์— ์ „์ฒด ์‹œ์Šคํ…œ์ค‘ ์–ด๋””์— ๋ฌธ์ œ๊ฐ€ ํŒŒ์•…ํ•˜๊ธฐ ์‰ฝ๋‹ค๋Š” ์žฅ์ ์ด ์ƒ๊ธด๋‹ค.
// ์—ฌ๊ธฐ์—์„œ๋Š” Mock์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค.
public void UpdateItem_changes_title(){
    
    // Arrange (Given) - ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋ฏธ๋ฆฌ ์ค€๋น„๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค
    IRepository repository = Mock.Of<IRepository>();
    var sut = new BusinessLayer(repository);
    int id = new Random().Next();
    string title = Guid.NewGuid().ToString();
 
    // Act (When) - ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ  ์‹ถ์€ ๊ณณ, ๋™์ž‘์ด ๋ฐœ์ƒํ•˜๋Š” ๊ณณ
    sut.UpdateItem(id, title);
 
    // Assert (Then) - ์›ํ•˜๋Š” ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ
    Mock.Get(repository)
        .Verify(x => x.Update(id, title), Times.Once());
}

 

 

@ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (Integration Test)

์‰ฝ๊ฒŒ๋งํ•˜๋ฉด ๋‹ค๋ฅธ ๊ณณ๊ณผ ๋…๋ฆฝ์ ์ด์ง€ ์•Š์€ ๊ทธ๋ƒฅ ํ…Œ์ŠคํŠธ. ์ƒˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ [๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค]๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ด๋ฏธ ์ž‘์„ฑ๋œ ๋‘˜ ์ด์ƒ์˜ ์‹œ์Šคํ…œ์ด ์กฐ๋ฆฝ๋˜์–ด ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•  ๋•Œ [ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค]๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. 

 

์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ฐ์ฒด๋“ค์„ ์‹ค์ œ๋กœ ๊ฐ™์ด ๋Œ๋ ค๋ดค์„ ๋•Œ ๋ฌธ์ œ์—†๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ชฉ์ ๋„ ์žˆ์ง€๋งŒ, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ฑ์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋„ ์—ฌ๊ธฐ์—์„œ ๊ฒ€์ฆํ•œ๋‹ค.

* ๋‹ค๋งŒ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋‹จ์œ„ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉํ…Œ์ŠคํŠธ๋ฅผ ๋‚˜๋ˆŒ ํ•„์š”๊ฐ€ ์—†๋Š”๋ฐ ์–ต์ง€๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ๋งŒ๋“œ๋Š”๊ฑด ์ข‹์ง€ ๋ชปํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ํ…Œ์ŠคํŒ…์˜ ๋ณธ์งˆ์€ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๋Š”์ง€, ์ด๊ฒŒ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์„ค๊ณ„์ธ์ง€, ์ž ์žฌ์ ์ธ ๋ฒ„๊ทธ๋Š” ์—†๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

 

@์ธ์ˆ˜, ์Šน์ธ ํ…Œ์ŠคํŠธ(Accpetance Test)

์ด๊ฒƒ๋„ ํ•œ๊ธ€๋กœ ๋ฒˆ์—ญํ•œ ์˜๋ฏธ๊ฐ€ ์ƒ๋‹นํžˆ ์–ด์ƒ‰ํ•˜๋‹ค. ์˜์–ด๋กœ๋Š” Acceptance Test

๋ง ๊ทธ๋Œ€๋กœ ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ๊ธฐํš๋Œ€๋กœ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ์ด๋‹ค. ์ผ์ข…์˜ ๋ธ”๋ž™๋ฐ•์Šค ํ…Œ์ŠคํŠธ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

โžก ๋‹จ์œ„, ํ†ตํ•ฉํ…Œ์ŠคํŠธ์—์„œ ๊ฒ€์ถœํ•˜๊ธฐ ์–ด๋ ค์šด ์‹œ์Šคํ…œ๋ฌธ์ œ, ์‹ค์ œ ์„œ๋น„์Šค ํ˜ธ์ŠคํŒ… ํ™˜๊ฒฝ๋“ฑ์„ ํ•จ๊ป˜ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

mocking ์—†์ด ์‹ค์ œ ์ „์ฒด ์„œ๋น„์Šค๋ฅผ ๋™์ž‘์‹œ์ผฐ์„ ๋•Œ ์ž˜ ๋Œ์•„๊ฐ€๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ

๋‹จ์œ„, ํ†ตํ•ฉํ…Œ์ŠคํŠธ๋งŒ ์ง„ํ–‰ํ•ด์„œ๋Š” ์ „์ฒด์„œ๋น„์Šค๊ฐ€ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์ฃผ๊ธฐ์ ์œผ๋กœ ์ธ์ˆ˜ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด์ค˜์•ผํ•œ๋‹ค.

 

๋‹ค๋งŒ ๋‹จ์œ„ํ…Œ์ŠคํŠธ, ํ†ตํ•ฉํ…Œ์ŠคํŠธ์™€ ๋‹ค๋ฅด๊ฒŒ ์‹ค์ œ๋กœ ๋ชจ๋“  ์„œ๋น„์Šค๊ฐ€ ๋™์ž‘ํ•˜๋Š”๊ฑฐ๋ผ ํ…Œ์ŠคํŠธ ์‹œ๊ฐ„์ด ๋งค์šฐ ๊ธธ๊ณ  ์–ด๋–ค ์ฝ”๋“œ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์ฐพ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.

โžก ๊ทธ๋ž˜์„œ ๋‹จ์œ„,ํ†ตํ•ฉํ…Œ์ŠคํŠธ๋Š” ๋Œ€๋ถ€๋ถ„ ์ž๋™ํ™”ํ•˜์ง€๋งŒ ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ํ•„์š”ํ•  ๋•Œ๋งŒ ์ˆ˜๋™์œผ๋กœ ์ง์ ‘ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

 

 

@ E2E, ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ(Functional Testing)

์ธ์ˆ˜ ํ…Œ์ŠคํŠธ(Acceptance Test)์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ํ•„์ˆ˜๋กœ ์ž๋™ํ™”ํ•ด์•ผํ•˜๋Š” ํ…Œ์ŠคํŠธ์ด๋‹ค. ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ๊ธฐ๋Šฅ๋“ค์„ ํ•˜๋‚˜์”ฉ ํ…Œ์ŠคํŠธํ•œ๋‹ค๋Š” ์˜๋ฏธ์—์„œ E2E(End to End) ํ…Œ์ŠคํŠธ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.

  • ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ๋‚ด๋ถ€์ฝ”๋“œ๋Š” ์ƒ๊ด€์—†๊ณ  ๊ธฐํš๋Œ€๋กœ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€๋งŒ ์ฒดํฌํ•˜๋Š” ๋ธ”๋ž™๋ฐ•์Šค ํ…Œ์ŠคํŠธ์ด๋‹ค.
  • ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ๋Š” ํ™”์ดํŠธ ๋ฐ•์Šค์ด๋‹ค. ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ๊ฐ ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ์‹ค์ œ ์„œ๋น„์Šค ํ™˜๊ฒฝ์—์„œ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•œ๋‹ค.
    โžก Mock ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์‹ค์ œ ๋ฐฐํฌํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๋ง๊ทธ๋Œ€๋กœ End-to-End๋ฅผ ๋‹ค ๊ฑฐ์น˜๋Š” ํ…Œ์ŠคํŠธ
public void UpdateCommand_changes_title_of_item()
{
    // Arrange
    var database = new SqlDatabase(...);
    int id = database.Insert("Hello World");
    string title = Guid.NewGuid().ToString();
 
    // Act
    ExecuteCommand($"Application.exe update {id} {title}");
 
    // Assert
    database
        .Execute("SELECT TITLE FROM ...")
        .Should().Be(title);
 
    // Cleanup
    database.Execute("DELETE ...");
}

 


# Mockist์™€ Classist

ํ˜„๋Œ€์˜ ๋„๊ตฌ๋“ค์—๋Š” ํ…Œ์ŠคํŠธ ๋”๋ธ”(test-double) ๊ฐ์ฒด๋“ค์˜ ๊ธฐ๋Šฅ์ด ์ •๋ง ๋‹ค์–‘ํ•˜๊ณ , ๋งค์šฐ ํŽธ๋ฆฌํ•˜๋‹ค.

  • ๋„๊ตฌ์˜ ์‚ฌ์šฉ์€ ์ •๋ง ํŽธํ•˜์ง€๋งŒ ๋ชจ๋“  ๊ณณ์— ํ…Œ์ŠคํŠธ ๊ฐ์ฒด๋ฅผ ๋‚จ๋ฐœํ•˜๋Š” Mockist์ธ ์‚ฌ๋žŒ๋“ค์ด ๋“ฑ์žฅํ•˜๊ณ  ์žˆ๋‹ค.
    โžก ๊ทน๋‹จ์ ์ธ ์˜ˆ๋กœ, [์‚ฌ์น™์—ฐ์‚ฐ +]๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ํ…Œ์ŠคํŠธ ๋”๋ธ”์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๋Š”๊ฑธ ์ƒ์ƒํ•ด๋ณด์ž.

ํ…Œ์ŠคํŠธ ๋Œ€์—ญ์€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š”๊ฑฐ์ง€, ๋ฌด์ž‘์ • ๊ฐ–๋‹ค์“ด๋‹ค๊ณ  ์ข‹์€๊ฒŒ ์•„๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋Œ€์—ญ์€ ์ผ์ข…์˜ ๊ฐ€์ •์ด๊ณ , ๊ฐ€์ •์ด ๋Š˜์–ด๋‚  ์ˆ˜๋ก ์‹ค์ œ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•˜๊ธฐ ๋” ์–ด๋ ค์›Œ์ง„๋‹ค.

 

Mockist์˜ ๋ฐ˜๋Œ“๋ง๋กœ ์‚ฌ์šฉ๋˜๋Š” Classist์˜ ์˜๋ฏธ๋Š”, ๋‹จ์ˆœํžˆ ๊ผฐ๋Œ€์ฒ˜๋Ÿผ

์—ฃ๋ผ! Mockito๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์“ฐ๋‹ค๋‹ˆ! ์ž๋ฐ”๋กœ๋งŒ ์ž‘์„ฑํ•ด!

๋ผ๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค. ํ•„์š”ํ•  ๋•Œ๋งŒ Test Double์„ ์“ฐ๋Š” ๊ฒƒ์ด ๋” ์ข‹์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด Presentation (์›น Controller) ๊ณ„์ธต์€ ์‚ฌ์šฉ์ž ์š”์ฒญ์„ Mockingํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๋Š”๊ฒŒ ๋งž๋‹ค.

ํ•˜์ง€๋งŒ Domain ๊ณ„์ธต์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๊ฐ€์ง„ ์ž๋ฐ” ๊ฐ์ฒด๋“ค๋งŒ ์ด๋ฃจ์–ด์ ธ์žˆ์œผ๋ฏ€๋กœ, ๊ตณ์ด Mock์„ ์“ฐ์ง€์•Š๋”๋ผ๋„ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 


# Mockist์™€ Classist๋ฅผ ์–ธ๊ธ‰ํ•˜๋Š” ์ด์œ 

์ด๊ทœ์›๋‹˜์˜ ๊ทธ๊ฒŒ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ผ๊ณ ? ์ •๋ง?์„ ์ฝ์–ด๋ณด๋ฉด ์™œ ์ด๊ฑธ ์–ธ๊ธ‰ํ–ˆ๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค1. ์กฐ๊ธˆ ๊ทน๋‹จ์ ์ธ ์ด์•ผ๊ธฐ
- ์ƒํ’ˆ๋“ค์˜ ๊ฐ€๊ฒฉ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•ด JSON์œผ๋กœ ์ถœ๋ ฅํ•˜๋Š” ์‹œ์Šคํ…œ์„ ์ž‘์„ฑํ•œ๋‹ค.
- ์ด ์‹œ์Šคํ…œ์˜ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š”๋ฐ JSON ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ Mockingํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‹น์—ฐํ•œ ์ด์•ผ๊ธฐ์ด๋‹ค.
์‹œ๋‚˜๋ฆฌ์˜ค2. ํ˜„์‹ค์ ์ธ ์ด์•ผ๊ธฐ
- ์„œ๋น„์Šค ์‹œ์Šคํ…œ๊ณผ ์ด๋ฅผ ์ด์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ ๋‹ค.
- ๊ฐ„๋‹จํ•˜๊ฒŒ ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ , ์„œ๋น„์Šค์™€ ํด๋ผ์ด์–ธํŠธ๋Š” ๋™์ผํ•œ ํ”„๋กœ์„ธ์Šค์—์„œ ๊ตฌ๋™๋˜๋Š” ๊ฐœ์ฒด์ด๋‹ค.
- ์„œ๋น„์Šค๋Š” API๋งŒ ๊ฐœ๋ฐœ ์™„๋ฃŒ๋˜์—ˆ๊ณ , ๋‚ด๋ถ€ ๊ตฌํ˜„์€ ์•„์ง ๊ฐœ๋ฐœ์ค‘์ด๋ผ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.
- ๊ทธ๋ž˜์„œ ํด๋ผ์ด์–ธํŠธ ๊ฐœ๋ฐœ์ž๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋น„์Šค ์‹œ์Šคํ…œ์„ Mockingํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๊ณ  ๋„˜์–ด๊ฐ”๋‹ค.

- ์ดํ›„ ์„œ๋น„์Šค์™€ ํด๋ผ์ด์–ธํŠธ๋Š” ๊ฐ๊ฐ ์„ฑ๊ณต์ ์œผ๋กœ ๋ชจ๋“  ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ์™„๋ฃŒํ•˜์˜€๋‹ค.
- ๊ทธ๋Ÿฐ๋ฐ ์ด ๋‘ ๊ฐœ๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผฐ์„ ๋•Œ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•จ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์„๊นŒ...?
- ๊ฒฐ๊ตญ Mocking์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ํ†ตํ•ฉํ…Œ์ŠคํŠธ๊ฐ€ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•˜๋‹ค.
์‹œ๋‚˜๋ฆฌ์˜ค3. ์ƒ๊ฐํ•ด๋ณผ ์ด์•ผ๊ธฐ
- ์‹œ๋‚˜๋ฆฌ์˜ค2์™€ ๋™์ผํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•˜์ง€๋งŒ, ์ด๋ฒˆ์—๋Š” ์„œ๋น„์Šค ์‹œ์Šคํ…œ๋ถ€ํ„ฐ ๋จผ์ € ๊ฐœ๋ฐœ๋œ๋‹ค.
- ์„œ๋น„์Šค ์‹œ์Šคํ…œ์ด ๋ชจ๋“  ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑํ•˜๊ณ , ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๊ฒ€์ฆ์„ ์™„๋ฃŒํ•œ๋‹ค.
- ์ด์ œ ํด๋ผ์ด์–ธํŠธ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ ๋‹ค.
- ์„œ๋น„์Šค ์‹œ์Šคํ…œ์€ ์ด๋ฏธ ํ…Œ์ŠคํŠธ ๊ฒ€์ฆ์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค. ๊ตณ์ด Mockingํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์‹ค์ œ ๊ฐ์ฒด๋กœ ํ…Œ์ŠคํŠธํ•œ๋‹ค.

- ํ•˜์ง€๋งŒ ๋‚˜๋ผ๋ฉด ์–ด๋–จ๊นŒ? ์ด ๊ฒฝ์šฐ์—๋„ ๋‹จ์ˆœํžˆ ํŽธ๋ฆฌํ•˜๋‹ค๋Š” ์ด์œ ๋กœ Mocking ํ•˜์ง€๋Š” ์•Š์•˜์„๊นŒ?
- ๊ทธ๋Ÿฌ๊ณ ๋‚˜์„œ ๋‹จ์œ„/ํ†ตํ•ฉ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€๋กœ ์ž‘์„ฑํ•˜์ง€๋Š” ์•Š์•˜์„๊นŒ?

ํ…Œ์ŠคํŠธ ๋Œ€์—ญ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ†ตํ•ฉํ…Œ์ŠคํŠธ์ธ๊ฒŒ ์•„๋‹ˆ๋‹ค. ์ด๋Ÿฐ ํ…Œ์ŠคํŒ…์˜ ์ƒ๋‹น์ˆ˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž‘์„ฑ์ด ํž˜๋“ค์–ด์ง€๊ฑฐ๋‚˜ ์‹คํ–‰ ๋น„์šฉ์„ ์ฆ๊ฐ€์‹œํ‚ค์ง€๋„ ์•Š๋Š”๋‹ค.

 

Mockist๊ฐ€ ๋˜์–ด ๋ฌด์ž‘์ • ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ์‹œํ‚ค๊ณ , Test-Double๋กœ ๋Œ€์ฒดํ•˜๋Š” ๋ฐ”๋ณด๊ฐ€ ๋˜์ง€๋ง์ž.

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ