[javascript] Riot.js에서의 테스트 전략

Riot.js는 가벼운 웹 컴포넌트 라이브러리로, 간단하게 컴포넌트 기반의 프론트엔드 앱을 구축할 수 있습니다. 하지만, 대규모 프로젝트에서는 테스트 전략을 잘 수립하는 것이 중요합니다. 이번 글에서는 Riot.js에서 효과적인 테스트 전략을 소개하겠습니다.

1. 유닛 테스트 작성하기

Riot.js에서의 유닛 테스트는 개별 컴포넌트의 기능을 테스트하는 것을 말합니다. 유닛 테스트는 각 컴포넌트의 메소드, 이벤트 핸들러 등을 테스트하여 예상한 대로 작동하는지 확인합니다.

예를 들어, HelloWorld 컴포넌트의 greeting 메소드를 테스트하는 코드는 다음과 같을 수 있습니다:

describe('HelloWorld', () => {
  it('should return the correct greeting', () => {
    const helloWorld = new HelloWorld();
    expect(helloWorld.greeting()).toBe('Hello, World!');
  });
});

describe 함수는 테스트 스위트를 정의하고, it 함수는 각 테스트 케이스를 정의합니다. expect 함수와 toBe 메소드를 이용하여 기대하는 결과와 실제 결과를 비교합니다.

2. 컴포넌트 렌더링 테스트하기

Riot.js에서의 컴포넌트 렌더링 테스트는 실제 DOM에 컴포넌트가 올바르게 렌더링되었는지 확인하는 것을 말합니다. 이를 위해 Riot.js의 mount 함수를 사용할 수 있습니다.

예를 들어, HelloWorld 컴포넌트가 올바르게 렌더링되는지 확인하는 코드는 다음과 같을 수 있습니다:

describe('HelloWorld', () => {
  it('should render the correct greeting', () => {
    const el = document.createElement('app');
    const helloWorld = riot.mount(el, 'hello-world')[0];
    expect(el.textContent).toBe('Hello, World!');
  });
});

mount 함수는 첫 번째 인자로 DOM 엘리먼트를, 두 번째 인자로 컴포넌트 태그를 받습니다. 이를 통해 hello-world 컴포넌트를 마운트하고, 해당 엘리먼트의 텍스트 콘텐츠가 예상한 대로 출력되는지 확인합니다.

3. 통합 테스트 작성하기

Riot.js의 통합 테스트는 여러 컴포넌트 간의 상호작용, 라우팅 등을 테스트하는 것을 말합니다. 이를 위해 실제 애플리케이션의 상태와 동작에 집중하여 테스트를 작성해야 합니다.

예를 들어, App 컴포넌트가 올바르게 동작하는지 확인하는 통합 테스트 코드는 다음과 같을 수 있습니다:

describe('App', () => {
  it('should render the correct components', () => {
    const el = document.createElement('app');
    const app = riot.mount(el, 'app')[0];
    expect(app.querySelectorAll('hello-world')).toHaveLength(1);
    expect(app.querySelectorAll('user-list')).toHaveLength(1);
  });
});

위 코드는 app 컴포넌트를 마운트하고, 해당 컴포넌트 내의 hello-worlduser-list 컴포넌트가 각각 한 번씩 렌더링되는지 확인합니다.

4. Mock과 Stub 활용하기

Riot.js의 테스트에서 외부 의존성을 가진 컴포넌트에 대한 테스트는 Mock과 Stub을 활용하여 가상의 데이터와 상호작용을 시뮬레이션할 수 있습니다. 이를 통해 외부 의존성의 영향을 받지 않고 테스트할 수 있습니다.

예를 들어, UserService로부터 사용자 목록을 불러오는 동작을 테스트하는 코드는 다음과 같을 수 있습니다:

describe('UserList', () => {
  it('should fetch and render the user list', async () => {
    const el = document.createElement('user-list');
    const userService = {
      fetchUsers: async () => [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' }
      ]
    };
    const userList = riot.mount(el, 'user-list', { userService })[0];
    
    await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for async data fetching
    
    expect(userList.querySelectorAll('li')).toHaveLength(2);
    expect(userList.querySelectorAll('li')[0].textContent).toBe('Alice');
    expect(userList.querySelectorAll('li')[1].textContent).toBe('Bob');
  });
});

위 코드에서는 userService 객체를 생성하여 fetchUsers 메소드를 Stub으로 대체하고, 가상의 사용자 목록을 반환하도록 설정합니다. 이를 통해 user-list 컴포넌트가 올바르게 데이터를 가져와서 렌더링하는지 테스트합니다.

결론

Riot.js에서의 효과적인 테스트 전략은 유닛 테스트, 컴포넌트 렌더링 테스트, 통합 테스트, 그리고 Mock과 Stub을 적절히 활용하는 것입니다. 이를 통해 Riot.js 애플리케이션을 안정적으로 유지하고, 변경 사항에 대한 신뢰성 있는 개발을 할 수 있습니다.

참고 자료: