반응형
Testing 2
들어봤을 법한 테스팅 용어
- Mutation Testing: 일부러 코드에 오류를 만들었을 경우 테스트가 멈추는가?
- Fuzz testing: random input을 매우 많이 넣어보기.
- DU-coverage: 각각의 <define x / use x> 쌍이 모두 실행되었는가?
- Symbolic execution
- Concolic testing: concrete + symbolic test
Mutationg-based Fuzz Testing example
예시 과정: 크롤링 - 퍼징 툴(스크립트)로 - grab & mutate file, Feed it to prog, rec if crashed.
Focus on Sets of Values
Path마다 그룹으로 나눠서 보기.(트리 그려가면서)
각 그룹마다 하나의 대표값 찾기.
Symbolic vs. Explicit Represintation
- 그 값의 성질들로 표현한 것 vs. 1:! 대응 시켜주는 것
Satisfiability
- A formula is satisfiable if there is a way to assign values to variables and make the formula
- A formula is unsatisfiable if every assignment of values to variables makes the formula false.
Solver
QA in Agile
- Antiquated for SaaS apps: Quality assurance is the responsibility of a separate group rather than the result of a good process.
- 개발자는 코드 테스팅과 코드 리뷰에 더욱 큰 책임을 져야함.
- QA 엔지니어는 테스팅툴 인프라를 개선시키고, 개발자가 더욱 testable한 코드를 작성할 수 있도록 도움. 사용자가 레포트한 오류가 재현 가능한지 검증해야함.
TDD
TDD 원칙들
- 테스트를 통과할 수 있도록, 코드를 작성해야함
- 순서가 바뀌어서 코드 작성 후, 작성된 코드를 검사하기 위한 테스트 코드를 작성하지 말 것!
- 테스트가 디자인과 구현 내용을 drive한다.
- 테스트 코드 작성에 시간을 투자하면 나중에 가서 (디버깅)시간을 절약할 수 있다.
- 물론 맹신은 금물.
TDD Reduces Bug Density
버그가 감소하지만, 테스트 코드 작성에 추가적인 시간 소요
TDD를 언제 적용하면 좋을까?
Good
- UI behavior
- 비즈니스 로직
- 자바의 클래스와 메서드 작성시
Bad
- UI 외형 테스트
- 클라이언트 / 서버 통신 (mock 테스팅이 필요한 경우임)
- 큰 코드베이스 / 레거시 코드에서 적용하기는 좋지 않음.
Test Double
Test Double for Unit Test
- 요구사항: 프로젝트가 잘 짜여진 구조로 설계되어야함. (ex: Dependency Injection하기 좋도록)
- stubs, mocks, fakes, dummies 등을 이용하여 전체 시스템을 테스트를 위해 잘라냄.(stub out parts of prj) => Test Double
Test Double
- Fake 객체는 실제 동작도록 구현한 것임. 그러나 실제 프로덕트랑은 거리가 있는 간편한 버전. (예시: InMemoryTestDatabase)
- Stub 은 canned answer임. 임의로 값을 정해둔 것.(예: stubInitialState)
- Spy 는 호출 방식에 따른 어떠한 정보를 저장하는 것.(예: 이메일 발송 개수 같은 것)
- Mock 는 어떤 함수나 클래스를 모방하는 것. pre-programmed with expectations. 어떤 값을 넣으면 어떤 값이 나오리라 예측. 예외를 throw할 수 있음. 특정 케이스에서 원하는 값이 나오는지 확인.
The Need for Test Double
interchangeably Mocking
- 유닛 테스트에서는 외부 의존성을 없애라. 이는 테스트에서 통제 가능한 환경을 만들도록 해줌.
- 우리가 테스트하려는 클래스와 interaction하는 모든 클래스들을 mock할 것임.
- 왜?
- 테스트 속도를 빠르게 해줌
- 원하지 않는 사이드 이펙트를 배제할 수 있다.Mocking이 필요한 것들
- 데이터 베이스 연결
- 웹 서비스
- 속도가 느린 클래스
- side effect가 있는 클래스
- non-deterministic(예측 불가능)한 behavior를 가지는 클래스
Mocking
- Fake class들은 이 외부 종속성들을 제거해 줄 수 있다.
- 실제 테스트가 시작되기 전에 instruction을 줘서 우리가 예상하는대로 행동하게 만들수 있음. (beforeAll, beforeEach)
Stubs
- stub은 pre-programmed된 값을 반환하는 가짜 클래스이다.
- 테스트 중 class에 injected되어 input 값에 대한 control을 우리에게 준다.
- 실제 DB없이 DB가 동작하는 시나리오 대로 value를 반환하는 DB connection이 대표적인 예시이다.
Mocks
- Mock은 테스트가 끝난 후, 테스트 중에 클래스(테스트 받는)와 어떤 상호 작용을 했는지 검사받을 수 있음.
- 몇 번 method가 실행되었는지, 실행되었는지와 같은 정보를 테스트 후 검증
- class with side effects가 대표적인 mock.
Mockito
- mocking framework for JUnit tests
How Do We Test CustomerReader?
- 어떤 DB와 연결된 클래스를 테스트한다고 하자.
- 이것을 테스트 할때는 실제 DB객체를 불러와서 테스트하는 경우, 클래스가 생성된 DB객체와 hard deoendency가 생김.
- completely remove the database dependency하는 것이 베스트.
- stub the database connection instead, and "fool" our class to think that it is talking to a real EntityManager, while in reality the EntityManager is a Mockito stub
Multiple Test Methods
- @before, 테스트 전에 외부 의존성 없애기 : mock하거나 stub 등 여러 방법으로.
- 여러 개의 method를 한번에 테스트 가능함.
테스트할 함수가 값을 반환하지 않는 경우
void
- 이 경우 사이드 이펙트에 집중하자.
Python Mock Library: unittest.mock
- Mock class 제공
- patch() 는 실제 객체를 Mock 인스턴스로 대체해줌. 데코레이터나 컨텍스트 매니저로 사용할 수 있음.
@patch('main.Calculator.sum', side_effect=mock_sum)
- 이외에도 pytest, monkeypatch와 같은 선택지도 있음.
Specification-style Testing
Spec-style Testing
- BDD:(high-level) 스토리 기반 테스팅
- spec-style testing: use functional specs
- describe()/beforeEach()/it()
- xUnit의 대안
- Jest: 자바스크립트 유닛 테스팅
- Jasmine: BDD testing framework for JSFE testing Tool We Use
- Jest
- suites, specs, expectations, matchers(toBe)
- mocks and spies
- Enzyme
- JS testing library for React
- render, access, and DOM 요소 조작
Jest
- describe/it/test
- expect, matcher(toBe, toEqual)
- before(after)Each(All)
someObject.someMethod = jest.fn(()=> {})
jest.spyOn(someObject, someMethodName).mockImplementation(() => customImplementation)
Jest/Jasmine
- Test suites: a collection of tests
describe('Component or Object', () => {})
- Spec: 개별 테스트
it('개별 테스트 설명',() => { 테스트 구현 })
test('개별 테스트 설명',() => { 테스트 구현 })
- Expectation and Matcher
expect(actualListOfTweetIds).toEqual(expectedListOfTweetIds);
- Setups
- reapeat: beforeEach(function(){}), afterEach(()=>{})
- One-time setup: beforeAll, afterAll
Testing Asynchronous Code
- When you have code that runs asynchronously, Jest needs to know when the code it is testing has completed, before it can move on to another test.
done => {.....; done() or done(error)}
로 끝나는 시점 표시해줘야함.
Mock
- jest.fn()
- jest.spyOn(objecg, methodName).mockImplementation(() => customImpl)
Enzyme
- shallow: shallow rendering, children 컴포넌트들은 렌더링하지 않음.
- mount: full rendering
- 리덕스의 경우 before을 통해 provider를 감싼다. 따라서 mount를 통해 완전히 렌더링한 다음, 우리가 원하는 컴포넌트 찾아야함.
- .find()를 통해 css selector에 따라 컴포넌트 선택 가능.
- simulate: simulate event
- 리덕스에 감싸진 경우, Enzyme을 통해 state에 접근하려는 경우
에서it(`should set state properly on title input`, () => { const title = 'TEST_TITLE' const component = mount(newTodo); const wrapper = component.find('input'); wrapper.simulate('change', { target: { value: title } }); const newTodoInstance = component.find(NewTodo.WrappedComponent).instance(); expect(newTodoInstance.state.title).toEqual(title); expect(newTodoInstance.state.content).toEqual(''); });
component.find(실제컴포넌트.WrappedComponent).instance();
와 같이 컴포넌트를 인스턴스화 해야함. - sinon: standalone test spies, stubs and mocks for JS
- chai: assertion library like Jest
반응형
'개발 > 학교 수업' 카테고리의 다른 글
[소개원실/swpp] Software Development Process (0) | 2021.10.12 |
---|---|
[소개원실] Requirements and Specification (0) | 2021.10.07 |
[소개원실] Project Sprints (0) | 2021.10.07 |
[소개원실] Testing (0) | 2021.09.28 |
[컴퓨터 비전] 과제를 위한 개발환경 세팅하기(Anaconda, vscode, pycharm) (0) | 2021.09.14 |