Code Monkey home page Code Monkey logo

shift-left-test-study's Introduction

shift-left-test-study

개발자를 위한 시프트 레프트 테스트 책 스터디입니다. 책을 읽으며 요약정리하고 테스트코드 예제를 짭니다.

목차

1주차

  • CHAPTER 1 테스트 시작하기
  • CHAPTER 2 시프트-레프트 테스트
  • CHAPTER 3 개발자 테스트의 기본 중 기본

2주차

  • CHAPTER 4 코드 기반 단위 테스트
  • CHAPTER 5 단위 테스트 효율화: 쉬운 단위 테스트
  • CHAPTER 6 기능 단위별 단위 테스트

3주차

  • CHAPTER 7 리팩터링
  • CHAPTER 8 코드 리뷰
  • CHAPTER 9 통합 테스트

4주차

  • CHAPTER 10 시스템 테스트의 자동화
  • CHAPTER 11 탐색적 테스트
  • CHAPTER 12 테스트 전체 설계

5주차

  • CHAPTER 13 애자일 및 시프트-레프트 지표
  • CHAPTER 14 애자일에서의 요구사항 사양
  • CHAPTER 15 개발자 테스트의 실제 샘플

PS) 기존에 진행했던 과제들은 git issue에서 확인하시면 됩니다. -> 제출한 과제들

shift-left-test-study's People

Contributors

silano08 avatar jong1co avatar

Watchers

 avatar

Forkers

jong1co

shift-left-test-study's Issues

5주차 과제 리뷰

3주차 과제

  • 테스트케이스 보완
    • 동시에 입금이 2회 이상 요청되고 있으면, 첫 입금이 수행되고 있었음
    • 위 케이스 커버하는 테스트 추가
  • Queue > exec 메서드 수정
    • 동시 입금 2회, 출금 1회 시 에러를 바로 반환하여 입금 1회만 수행되고 있었음
    • 입금인 항목만 걸러 유효하지 않은 횟수만큼 콘솔 출력
    • 입금이 아닌 항목들은 정상적으로 실행�
    • 리팩터링

4주차 과제

3주차 과제 리뷰

구현 대상(ReadMe)

https://github.com/silano08/synchronize-user-balance

테스트를 위한 의사 결정 테이블

image

-> 여기서 주요 요청사항은 동시요청이니 동시요청만 구현함

테스트 작성


    @Test
    void increaseSameTime() throws Exception {
        Long accountId = bankAccountRepository.findAll().get(0).getId();
        int threadCount = 2; // 동시에 2개의 입금 요청
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CountDownLatch latch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                try {
                    balanceFacade.increase(accountId, 1000L);
                    System.out.println("Deposit successful");
                } catch (Exception e) {
                    System.out.println("Deposit failed: " + e.getMessage());
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await(); // 모든 입금 요청이 완료될 때까지 대기
        executor.shutdown();

        BankAccount updatedAccount = bankAccountRepository.findById(accountId).orElseThrow();
        assertEquals(10000L, updatedAccount.getBalance()); // 동시 입금 요청에 대한 실패 예상으로, 잔액은 변하지 않아야 함
    }


    @Test
    void decreaseSameTime() throws Exception {
        //  잔고 출금 요청이 동시에 2개 이상 올 경우 차례대로 실행
        Long accountId = bankAccountRepository.findAll().get(0).getId();
        ExecutorService executor = Executors.newFixedThreadPool(2);

        CompletableFuture<Void> withdrawal1 = CompletableFuture.runAsync(() -> {
            try {
                balanceFacade.decrease(accountId, 1000L);
                System.out.println("Withdrawal 1 successful");
            } catch (Exception e) {
                System.out.println("Withdrawal 1 failed: " + e.getMessage());
            }
        }, executor);

        CompletableFuture<Void> withdrawal2 = CompletableFuture.runAsync(() -> {
            try {
                balanceFacade.decrease(accountId, 1000L);
                System.out.println("Withdrawal 2 successful");
            } catch (Exception e) {
                System.out.println("Withdrawal 2 failed: " + e.getMessage());
            }
        }, executor);

        CompletableFuture.allOf(withdrawal1, withdrawal2).join();
        executor.shutdown();

        BankAccount updatedAccount = bankAccountRepository.findById(accountId).orElseThrow();
        assertEquals(8000L, updatedAccount.getBalance());
    }


    @Test
    void increaseAndDecreaseSameTime() throws Exception {
        //  잔고 입금과 출금 요청은 동시에 올 수 있고, 요청 온 차례대로 실행
        // 입금->출금 , 출금->입금으로 로직 작성할 것

        Long accountId = bankAccountRepository.findAll().get(0).getId();
        ExecutorService executor = Executors.newFixedThreadPool(2);

        CompletableFuture<Void> deposit = CompletableFuture.runAsync(() -> {
            try {
                balanceFacade.increase(accountId, 1000L);
                System.out.println("Deposit successful");
            } catch (Exception e) {
                System.out.println("Deposit failed: " + e.getMessage());
            }
        }, executor);

        CompletableFuture<Void> withdrawal = CompletableFuture.runAsync(() -> {
            try {
                balanceFacade.decrease(accountId, 1000L);
                System.out.println("Withdrawal successful");
            } catch (Exception e) {
                System.out.println("Withdrawal failed: " + e.getMessage());
            }
        }, executor);

        CompletableFuture.allOf(deposit, withdrawal).join();
        executor.shutdown();

        BankAccount updatedAccount = bankAccountRepository.findById(accountId).orElseThrow();
        assertEquals(10000L, updatedAccount.getBalance());
    }

리팩토링

(로직 수정만으로도 벅차서 아직 못함)

해결못한문제

입금 두번 시 실패

이게 너무 어려웠음.. 트랜잭션을 관리한다고할때 보통은 동시에 요청이 들어오면 트랜잭션을 차지한 하나는 성공 다른 하나는 실패 이게 일반적인 로직인데 둘다 실패라는건 이전 트랜잭션을 관리해야하는거라 로직을 계속 수정해도 실패했음.

어플리케이션 단위에서 추천하는 동시 실패 메커니즘은 이 두개였는데 두번째 방식의 구현이 더 쉬워보여서 두번째로함

  1. 모든 트랜잭션을 롤백시키기 위한 로직 추가: 모든 트랜잭션이 실패하도록 처리하려면, 첫 번째 트랜잭션이 성공적으로 커밋된 후에도 조건에 따라 롤백할 수 있는 메커니즘을 구현해야 합니다. 이는 일반적으로 복잡하고, 종종 구현하기 어려울 수 있습니다. 예를 들어, 첫 번째 트랜잭션 후 일정 시간을 기다렸다가 다른 트랜잭션이 수행되지 않았는지 확인하고, 수행되었다면 롤백을 시도하는 방식입니다.

  2. 초기 요청에서 동시성을 체크하고 모두 거부하기: 더 간단한 방법은 요청을 받자마자 동시성을 체크하고, 어떠한 요청도 수행되지 않도록 하는 것입니다. 이를 위해 각 요청의 시작 시점에서 동시성 검사를 수행하고, 어떤 요청도 진행되지 않도록 할 수 있습니다. 이는 기존의 AtomicInteger 방식을 수정하여, 단 한 번의 요청도 성공하지 못하도록 하는 것입니다.

2번째 방식으로 해결했는데 해당 코드는 여기서 확인(드디어 성공ㅠㅠ)
silano08/synchronize-user-balance@5b5656d

그리고

인프라단계에서의 동시성

어플리케이션 단계에서의 동시성은 고려가능하지만.. 다중 인스턴스를 주로 쓰는 실무환경에선 내가 작성한 로직을 적용하기 어려울수도있겠구나싶음

5주차 과제 리뷰

369게임 이전에 작성하던것 마무리함

개요

https://github.com/silano08/369game

멀티 스레드로 동작하도록 코드 추가 및 지역명 return하는 인터페이스 추가

silano08/369game@59f9bdf

동시성 메소드 추가

silano08/369game@e1f42ee

테스트 코드

silano08/369game@2f93c91

조건 커버리지

  1. 플레이어가 박수를 쳐야 하지만 숫자를 말하는 경우
  2. 플레이어가 숫자를 말해야 하지만 박수를 치는 경우
  3. 플레이어가 정상적으로 숫자를 말하는 경우
  4. 플레이어가 정상적으로 박수를 치는 경우

동시성 테스트

얘는 별건없고.. main에 있던거 테스트코드로 옮겨놓음

2주차 과제 리뷰

과제 : 숫자야구

https://github.com/silano08/java-baseball-6?tab=readme-ov-file

1차적으로 로직 작성

silano08/java-baseball-6@c33ada9

기능 중 일부 경곗값 테스트 작성 (유저가 숫자를 입력하는 부분, 숫자를 맞추는 부분 출력값)

silano08/java-baseball-6@b27cbc9

구조 패턴 중 facade패턴 코드에 적용 및 리팩토링

silano08/java-baseball-6@3e2a2fb

생성패턴 중 Singleton패턴으로 적용 및 리팩토링

silano08/java-baseball-6@4e6a500

4주차 과제 리뷰

1. 코드

https://github.com/silano08/369game

기본기능 구현
silano08/369game@a45a2b7

2. 디자인 패턴 적용 : 전략패턴

silano08/369game@731707f

참조 : https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EC%A0%84%EB%9E%B5Strategy-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90#strategy_pattern

3. 테스트코드 적용

do369에 대한 단위테스트 : silano08/369game@33de267
전략패턴에 대한 테스트 작성 : silano08/369game@ef6b5a8

4. 리팩토링

모킹을 위한 랜덤함수 소스코드 분리 : silano08/369game@0368e34

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.