Cần review cách viết unit test

Chào mọi người, mình đang tập tành viết unit test cho 1 thư viện của mình, cơ mà không biết phải viết sao cho đúng.

Ví dụ mình có function này.

function trimLeft(str: string, char: string): string {
	if (str === '')
		return ''
	let pos = 0
	while (str[pos] === char[0])
		pos++
	return str.substring(pos)
}

Và đây là test mình viết được.

describe('Trim left function', () => {
	it.each([
		['', '', ''],
		['abc', '', 'abc']
	])('should not change when no char to trim',
		(str: string, char: string, expected: string) => {
			expect(trimLeft(str, char)).toBe(expected)
		})

	it('should returns empty when input is empty', () => {
		expect(trimLeft('', 'a')).toBe('')
	})

	it('should not change when input does not start with the specified char', () => {
		expect(trimLeft('abc', 'x')).toBe('abc')
	})

	it.each([
		['abc', 'a', 'bc'],
		['aaabc', 'a', 'bc'],
		['aaa', 'a', '']
	])('should trim all specified char on the left',
		(str: string, char: string, expected: string) => {
			expect(trimLeft(str, char)).toBe(expected)
		})

	it('should use the first char to trim only', () => {
		expect(trimLeft('abc', 'ab')).toBe('bc')
	})
})

Mình muốn hỏi là code test như trên có điểm nào không đúng hay cần cải thiện gì không?

Ngoài ra mình cũng có 1 số thắc mắc về việc test trong thực tế sẽ như thế nào. Cần test với các input như thế nào, có phải nhìn code rồi viết test dựa theo các if else, có nên expect nhiều lần trong 1 test case hay không? Ngoài ra một số trường hợp đặc biệt như 1 function gọi 1 function khác theo điều kiện thì test thế nào,…?

Thanks.

Tớ không rành lắm về convention của unit test trên javascript, vậy nên tớ sẽ skip phần đó nha :smile:

  • Cậu chưa test trường hợp pass null vào từng argument của function của cậu.
  • Cậu chưa test trường hợp trim ‘abc’ với ký tự b hoặc c.
    Test này sẽ giống với test trim ‘abc’ với ‘x’, cơ mà nó đóng vai trò safety net cho cậu, trong TH ai đó refactor sai function của cậu.
  • Với TH ký tự được truyền vào có 2 ký tự, có lẽ cậu nên báo lỗi hơn là chỉ pick ký tự đầu.
    Phần này tùy thuộc vào ý đồ design của cậu cho function đó nha :smile:

Cậu sẽ có 2 approach để viết test trong thực tế:

  1. Test-first (a.k.a Test driven development - cậu viết test trước khi implement).
  2. Test sau khi implement.

Nếu cậu đã biết cách implement, cậu nên implement luôn, sau đó viết test để đảm bảo cậu không sót TH nào, cũng như giúp cho hoạt động maintain, refactor trong tương lai.
Nếu cậu vẫn còn đang mập mờ, chưa biết implement như thế nào, chỉ biết yêu cầu cài đặt là gì, cậu nên viết test trước.
Ngoài ra, unit test được design để test từng đơn vị, nên nó cần độc lập nhất có thể.

Thông thường, cậu sẽ viết test để cover hết các scenario có thể xảy ra mà method của cậu đang được design để xử lý, bao gồm cả các kịch bản lỗi (nếu cậu follow TDD), còn không, cậu sẽ viết test để cover hết các nhánh (khi cậu đã có implement sẵn rồi).
Nếu cậu chưa có nhiều kinh nghiệm, cậu nên:

  • Lập bảng chân trị dựa trên argument và các yếu tố liên quan.
    Từ bảng này, cậu sẽ đưa ra list các test để có thể bao phủ hết các TH, cũng như bao phủ nhánh.
  • Test các giá trị biên của argument.
  • test TH null argument (trừ TH cậu có constract không bao giờ pass null vào method by default)
  • test TH các yếu tố mà method này phụ thuộc trả về lỗi.

Đó là kiểm thử hộp trắng đó :smile:
Cậu cũng có thể viết các test dựa trên spec của method.

Có thể làm điều đó, miễn là test của cậu đủ dễ đọc, dễ hiểu.

Function được gọi (callee) kia nếu đủ đơn giản, và đã có test đầy đủ rồi, thì cậu chỉ cần bao phủ các nhánh của caller thôi.
Nếu callee là private method, cậu có thể test chung với caller.
Nếu callee rất phức tạp (như gọi tới external resource nào đó và trả về kết quả), cậu nên mock giá trị trả về của callee.
Nếu caller chỉ delegate sang callee, cậu không cần test caller, do nó không có logic gì để test.

Hope it helps!

5 Likes

Cảm ơn cậu về câu trả lời quá là chi tiết luôn.

Do project mình dùng typescript, nên gọi function mà pass null vào thì sẽ báo lỗi (trừ khi type có union với null), nên mình không test trường hợp đó.

3 Likes

Oh :smile:
Tớ không biết điều đó. Cảm ơn cậu đã chỉ cho tớ nha :smile:

4 Likes

Câu hỏi đặt ra là với code trên thì bao nhiêu test case thì sẽ cover được code đó,?
Cái này chắc nhiều bạn QC trả lời được: Calculate Cyclomatic Complexity.
Và dùng chỉ số này để biết code có tốt hay ko.


https://www.guru99.com/cyclomatic-complexity.html
Có thể dùng sonarqube cho toàn bộ pj để ra được chỉ số Cyclomatic Complexity.

4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?