Unit test cho MobX State Tree với Jest trong React Native
Jest
Jest là 1 thư viện testing, được tạo bởi Facebook và được viết bằng Javascript. Mục tiêu ban đầu được viết ra để phục vụ riêng cho ReactJs, thế nhưng vì tính đa dụng của nó nên đã trở thành thư viện testing cho ứng dụng viết bằng Javascript.
Jest có thể dùng để viết test cho UI component và cả logic của chức năng, như tiêu đề bài viết, mình chỉ nói về phần test chức năng.
Cài đặt
Từ phiên bản react native 0.38, khi tạo mới project react native đã có sẵn Jest rồi nên bạn không cần phải cài thêm bất cứ thứ gì. Nếu muốn biết thêm chi tiết, bạn có thể vào Jest tutorial React Native để đọc thêm.
Tạo project
Như những bài viết trước đã nói, ở đây mình dùng ignite-cli để tạo project mới(dĩ nhiên sẽ có Jest và MobX State Tree). Nếu bạn chưa đọc thì có thể ghé qua bài viết của mình.
$ npx ignite-cli new DemoJest
Chạy yarn test
sẽ cho kết quả như sau
Tạo Model
Model là nơi thực hiện xử lý logic của App, bạn viết phần xử lý của chức năng ở đây. Thay vì tạo bằng tay, ignite-cli có lệnh để tạo ra các file cơ bản của 1 file Model:
$ ignite g model user
Thư mục sau khi tạo bằng lệnh trên
user
│── user.props.ts
│── user.test.props
└── user.ts
Dưới đây là ví dụ về Model User:
export const UserModel = types
.model("User")
.extend(withEnvironment)
.props({
loading: types.optional(types.boolean, false),
data: types.optional(types.array(Data), []),
error: types.maybeNull(types.string),
})
.actions((self) => ({
setLoading: (loading: boolean) => {
self.loading = loading
},
setError: (error: string) => {
self.error = error
},
setData: (data: DataProps[] | []) => {
self.data.replace(data)
},
}))
.actions((self) => ({
getListUsers: flow(function* () {
self.setLoading(true)
const result = yield self.environment.api.getListUser()
if (result.kind === "ok") {
self.setData(result?.data?.data)
} else {
self.setError(result.data)
}
self.setLoading(false)
}),
}))
Giải thích 1 chút về các hàm:
setLoading
: param có kiểu là boolean. Khi được gọi đến sẽ thay đổi giá trịloading
dựa vào param.setError
: param có kiểu là string. Khi được gọi đến sẽ thay đổi giá trịerror
dựa vào param.setData
: param có kiểu là 1 mảng DataProp(được định nghĩa trước đó) hoặc 1 mảng rỗng. Khi được gọi đến sẽ thay thế giá trịdata
dựa vào param.getListUsers
: hàm lấy danh sách user. Khi được gọi đến, hàm này hoạt động như sau:- Chạy hàm setLoading với param là true.
- Gọi đến API để lấy dữ liệu từ server, nếu lấy được dữ liệu từ server thì gọi hàm
setData
với param là dữ liệu lấy được, còn có lỗi xảy ra thì gọi hàmsetError
với param là lỗi từ phía server trả về. - Chạy hàm setLoading với param là false.
Viết test
Trước khi viết test, cần khởi tạo Model bên trong hàm beforeEach với mock environment.
beforeEach(() => {
const mockEnvironment = {
api: {
getListUser: jest.fn(),
}
}
instance = UserModel.create({}, mockEnvironment)
})
Viết test cho action đơn giản trước:
Hàm test(name, function, timeout)
nhận vào 3 tham số:
- name: tên của test.
- function: hàm chứa các kỳ vọng sau khi chạy test mong muốn đạt được.
- timeout(optional): thời gian chờ (tính bằng mili giây) để chỉ định thời gian chờ trước khi hủy bỏ(mặc định là 5000ms).
test("test setLoading", () => {
instance.setLoading(true)
expect(instance.loading).toEqual(true)
})
- expect(prop).toEqual(value): mong muốn
prop
có giá trị bằng vớivalue
Tương tự, ta viết test cho 2 actions còn lại như sau:
test("test setError", () => {
instance.setError("Error found")
expect(instance.error).toEqual("Error found")
})
test("test setData", () => {
instance.setData([])
expect(instance.data).toEqual([])
})
Tiếp tục viết test cho trường hợp lấy dữ liệu từ server thành công:
const resultSuccess = {
kind: "ok",
data: {
data: [],
message: "",
success: true,
},
}
test("test getListUsers success", async () => {
instance.environment.api.getListUser.mockReturnValue(Promise.resolve(resultSuccess))
await instance.environment.api.getListUser(0)
expect(instance.environment.api.getListUser).toHaveBeenCalledWith(0)
expect(instance.data).toEqual(resultSuccess.data.data)
expect(instance.loading).toEqual(false)
})
- mockReturnValue(value): gán cho hàm được gọi trả về giá trị
value
- expect(function).toHaveBeenCalledWith(param): mong muốn hàm
function
được gọi với đối sốparam
Tương tự với viết test cho trường hợp lấy dữ liệu từ server không thành công
const resultFail = {
kind: "fail",
data: "",
}
test("test getListUsers fail", async () => {
instance.environment.api.getListUser.mockReturnValue(Promise.resolve(resultFail))
await instance.environment.api.getListUser(0)
expect(instance.environment.api.getListUser).toHaveBeenCalledWith(0)
expect(instance.error).toEqual("Error")
expect(instance.loading).toEqual(false)
})
Cuối cùng là chạy yarn test
sẽ đựợc
Tổng kết
Hy vọng qua bài viết này, bạn hiểu hơn về jest và có thể áp dụng nó trong project của mình.