TDD 예제(2)

 

 

두 번째 비동기 통신 예제로 살펴보는 독립성을 유지한 간략한 테스트 코드를 작성해보자.

테스트 코드를 작성할 때 어떤 측면을 검증할 지를 정하는 것이 첫 번째다. 

 

1. 함수의 호출 여부 확인

2. 반환값의 정확성을 확인

 

Mock은 테스트를 위한 가짜 객체를 생성하여, 실제 구현 대신 사용함으로써 테스트의 독립성과 신뢰성을 높이는 데 도움을 준다. 

 

# product_client.js

class ProductClient {
  async fetchItems() {
    const response = await fetch('http://example.com');
    return response.json();
  }
}

module.exports = ProductClient;

 

# product_service.js

const ProductClient = require('./product_client.js');

class ProductService {
  constructor() {
    this.productClient = new ProductClient();
  }

  async fetchAvailableItems() {
    const items = await this.productClient.fetchItems();
    return items.filter((item) => item.available);
  }
}

module.exports = ProductService;

 

product_service.js에서 ProductService 클래스는 product_client.js에 작성된 Product_Client클래스 인스턴스를 사용하고 있다.

 

여기서 검증하고 싶은 것은 ProductService 클래스 내에 fetchAvailableItems 메서드만 테스트를 해보고 싶은 것이다.

 

const ProductService = require('../product_service.js');
const ProductClient = require('../product_client.js');
jest.mock('../product_client.js');

describe('ProductService', () => {
  const fetchItems = jest.fn(async () => [
    { item: 'Milk', available: true },
    { item: 'banana', available: false },
  ]);

  ProductClient.mockImplementation(() => {
    return {
      fetchItems,
    };
  });
  let productService;

  beforeEach(() => {
    productService = new ProductService();
  });

  it('should filter out only available items', async () => {
    const items = await productService.fetchAvailableItems();
    expect(items.length).toBe(1);
    expect(items).toEqual([{ item: 'Milk', available: true }]);
  });
});

 

1. jest.mock('../product_client.js');

- ProductClient 모듈을 모킹하여 실제 네트워크 요청을 방지함으로써 이를 통해 테스트가 독립적으로 실행될 수 있도록 한다.

 

2. const fetchItems = jest.fn(async () => [...]);

fetchItems를 모킹하여 product_client를 mock한 결과값을 임의로 설정한다.

 

3. ProductClient.mockImplementation(() => {...});

mockImplementation하여 ProductClient의 인스턴스를 생성할 때 fetchItems가 포함된 객체를 반환할 수 있도록 지정한다. 이렇게 하면 테스트 중에 fetchItems가 호출되면 모킹이 구현된다.

 

4. beforeEach(() => { productService = new ProductService(); });

각 테스트가 실행되기 전에 새로운 ProductService 인스턴스를 생성함으로써, 각 테스트의 독립성을 보장한다. 이로 인해 이전 테스트의 상태가 다음 테스트에 영향을 미치지 않는다.

 

5. it('should filter out only available items', async () => {...});

fetchAvailableItems 메서드가 사용 가능한 항목만 반환하는지 확인한다.