-
Notifications
You must be signed in to change notification settings - Fork 1
๐งช Hyunduxโtest: ์ํ๊ด๋ฆฌ ํ ์คํธ
Dunk edited this page Aug 25, 2024
·
1 revision
ํด๋ผ์ด์ธํธ ์ํ๊ด๋ฆฌ ํด์ธ hyundux์์ given when then์ ํจํด์ ๊ธฐ์ค์ผ๋ก state๋ฅผ spreadํ์ง ์๊ณ ๊ฐ state์ ๋์๋๋ ๋ชจ๋ ์ํฉ์ ํ ํ์ผ์์ ๊ด๋ฆฌํ๋ ๊ฒ์ ์์น์ผ๋ก ํ๋ test ๋ชจ๋์ด๋ค.
- given when then: ์ด 3๊ฐ์ง ํ ์คํธ ์์น์ ๋ฐํ์ผ๋ก ํ ์คํธ๊ฐ ํ๋ ค๋ ์ด์ ์ํ์ ๊ฒฐ๊ณผ ์ํ๊ฐ ๋ช ํํ ๋ณด์ธ๋ค.
- ์์ํจ์: hyundux์ reducer๋ ํ์ฌ์ ํ ๋น๋ state ์๋ง ๋ฐ์ํ๋๋ฐ ์ด๋ ์ค๋ก์ง ์์ํจ์๋ก๋ง ๋ง๋ค์ด์ก๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด hyundux๊ฐ testableํ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ์ต๋ํ ์ด์ฉํ๊ณ ์ ํ์๋ค.
const tester = createHynduxTester(initFindingGameState, findingGameReducer);
test("๊ฒฐ๊ณผ๋ณด์ฌ์ง๋ ๊ฒ๋ค์ ์ธ๋ฑ์ค๋ณ๊ฒฝ_์
๋ ฅ๊ฐ:1 -> ๊ฒฐ๊ณผ๊ฐ 1 (์ฎ์ ํ
์คํธ)", () => {
const givenData = initFindingGameState.payload;
const whenData: Action = action.changeShowingAnswer(1);
const thenData = tester.makeThenPayload({ answerIndex: 1 })
tester.given(givenData).when(whenData).then(thenData, true);
});
- givenData: ์ฃผ์ด์ง ๋ฐ์ดํฐ (์ ์ฝ๋์ ๊ฒฝ์ฐ initState๋ฅผ ๊ฐ์ง๊ณ ์๋ค.)
- whenData: action์ด ์ฃผ์ด์ง๋ฉด givenData๋ฅผ ๋ณ๊ฒฝํ๋ ์ญํ ์ ํ๋ค.
- thenData: expected Data๋ผ๊ณ ๋ ํ ์ ์๋ค.
- tester.given().when().then(): ์ด๋ ์ฃผ์ด์ง ํ ์คํธ์ ์ํ์ ์ก์ ๋ค์ ๋ช ํํ ๊ฐ์ํ ํด์ฃผ๋ ์ญํ ์ ํ๋ค. then์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ ํด๋น ํ ์คํธ์ ๊ฒฐ๊ณผ๋ฅผ ์์ํด์ ์ ๋๋ค.
export class HyunduxTest<T> {
store: Store | null = null;
currentState: State<T> | null = null;
currentAction: Action | null = null;
resultState: State<T> | null = null;
constructor(initState: State<T>, reducer: Reducer<T>) {
this.store = createStore();
this.currentState = initState;
if (this.store !== null) {
this.store.subscribe(initState, reducer, (newState) => {
this.resultState = newState;
});
}
}
makeThenPayload(payLoad: object) {
return { ...this.currentState.payload, ...payLoad };
}
given(givenPayload: T) {
this.store.states = [createState(this.currentState.type, givenPayload)];
if (this.store !== null && this.currentState !== null) {
this.currentState = createState(this.currentState.type, givenPayload);
}
return this;
}
when(action: Action) {
this.currentAction = action;
return this;
}
async then<T>(expectedPayload: T, isTrue: boolean = true) {
if (this.currentAction != null &&
this.store !== null &&
this.currentState !== null
) {
this.store.states = [this.currentState];
await this.store?.dispatch(this.currentAction);
if (this.resultState !== null) {
if (isTrue) {
expect(this.resultState?.payload).toEqual(expectedPayload);
} else {
expect(this.resultState?.payload).not.toEqual(expectedPayload);
}
}
}
}
}
given, when, then ํจํด์ ๊ธฐ์ค์ผ๋ก ํ์ฌ ๊ฐ์ฒด๊ฐ ๊ฐ์ง๋ ๋ณ์๋ค์ ๋ฐ๊พธ๋ฉด ๋ง์ง๋ง then์ ์คํ์ ๋๋ ์ญํ ์ ํ๋ค. ์ฆ given, when, then์ ๋ช ์์ ์ด ํจ์์ด๋ค.
๋๋๊ฒ๋ Hyundux-saga๋ ๋จ์ํ API์ action์ ์ฐ๊ฒฐํ๋ ์ญํ ์ ํ๊ธฐ ๋๋ฌธ์ ํ ์คํธํ ๋๋ ๊ธฐ์กด action๊ณผ ๋๊ฐ์ด ๋ค๋ฃฐ ์ ์๋ค.
test("Test Title", () => {
const givenData = initFindingGameState.payload;
const whenData: Action = action.click({ request: {
answerList: [
{ positionX: 0.5, positionY: 0.5 },
]
}, response: {
responseCode: 1000,
message: "success",
data: {
ticketIryd: "1212",
startTime: "asdsad",
correctAnswerList: [
{
positionX: 0.5,
positionY: 0.5,
descriptionImageUrl: "",
title: "",
content: ""
}
]
}
}})
const thenData = tester.makeThenPayload({ showingAnswers: [{
positionX: 0.5,
positionY: 0.5,
descriptionImageUrl: "",
title: "",
content: ""
}]})
tester.given(givenData).when(whenData).then(thenData, true);
});
๋๋๊ฒ๋ click action์ saga์์ ์ฌ์ฉํ๋ action์ธ๋ฐ ์์ฒ๋ผ mock ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด๋ ์ ํ ์คํธ ๋๋ค.
- saga์ test๋ ํน์ ์๊ฐ์ test๋ฅผ ๊ฑธ ์ ์๋๋ฐ ๊ทธ ์ ์ ๋งค์ฐ ํฐ ์ฅ์ ์ธ๊ฑฐ๊ฐ๋ค(generate function์ด๊ธฐ ๋๋ฌธ์ด๊ธด ํ์ง๋ง...)
- ์ค์ hyundux-saga์ ๋ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํด๋ณผ ์ ์๋ ํ ์คํธ ๋ชจ๋๋ ํ์๋กํ ๊ฒ ๊ฐ๋ค.