• Khi XD 1 CT lớn, 1 LTV chuyên nghiệp sẽ dành thời gian cho việc viết test code không ít hơn tg dành cho viết bản thân CT • LTV chuyên nghiệp là người có khả năng, kiến thức rộng về c
Trang 1TESTING
Trang 2• Khi XD 1 CT lớn, 1 LTV chuyên nghiệp sẽ
dành thời gian cho việc viết test code
không ít hơn tg dành cho viết bản thân CT
• LTV chuyên nghiệp là người có khả năng,
kiến thức rộng về các kỹ thuật và chiến
lược testing
Trang 3Testing and debugging
• Testing & debugging i cùng v i nhau nh 1 đ ớ ư
c p: ặ
• Testing tìm errors; debugging định vị và sửa chúng.
• Ta có mô hình “testing/debugging cycle”:
Ta test, rồi debug, rồi lặp lại.
• Bất kỳ 1 debugging nào nên được tiếp theo
là 1 sự áp dụng lại của hàng loạt các tests liên quan, đặc biệt là các bài tests hồi quy Điều này giúp tránh nảy sinh các lỗi mới khi debugging
• Testing & debugging không nên được thực hiện bởi cùng 1 người (thường là không nên).
Trang 4Khái ni m Testing ệ
• Beizer: Vi c th c hi n test là ệ ự ệ để ch ng minh ứ tính úng đ đắ n gi a 1 ph n t và các ữ ầ ử đặ c t c a ả ủ nó.
s khác bi t gi a k t qu mong ự ệ ữ ế ả đợ i và k t qu ế ả
th c t ự ế
Trang 5Right/Wrong Specification
?
Trang 6Probably Right/Wrong Specification
Trang 7External vs Internal Testing
Trang 8External Testing
• External testing: TK d li u ữ ệ để test CT
• External testing taxonomy
(1) Kiểm chứng giá trị biên : Boundary
testing
(2) Kiểm chứng lệnh : Statement testing
(3) Kiểm chứng có hệ thống : Path testing
(4) Stress testing
Trang 9Boundary Testing
(1) Boundary testing
• “Là kỹ thuật kiểm chứng sử dụng các giá trị nhập vào ở trên hoặc dưới một miền giới hạn của 1 đầu vào và với các giá trị đầu vào
tạo ra các đầu ra ở biên của 1 đầu ra.”
‒ Glossary of Computerized System and Software Development Terminology
• Còn g i là ki m tra i u ki n biên- ọ ể đ ề ệ corner case testing
Trang 10Boundary Testing Example
• VD : đọ c 1 dòng t stdin và ừ đư a vào m ng ký t ả ự
• Boundary conditions
• Dòng rỗng -Input starts with '\n'
• In ra empty string (“\0”) => in ra “||” , ok
• Nếu gặp EOF - End of file trước '\n‘
• Ti p t c g i getchar() và l u ế ụ ọ ư ӱ vào s[i]
• Nếu gặp ngay EOF (empty file)
• Ti p t c g i getchar() và l u ế ụ ọ ư ӱ vào s[i]
Trang 11Boundary Testing Example (cont.)
• Boundary conditions (tt)
• Dòng chứa đúng MAXLINE-1 ký tự
• In ra úng, v i ‘\0’ t i s[MAXLINE-1]đ ớ ạ
• Dòng chứa đúng MAXLINE ký tự
• Ký t cu i cùng b ghi è, và dòng m i không bao gi c ự ố ị đ ớ ờ đ đọc
• Dòng dài hơn MAXLINE ký tự
Trang 12Boundary Testing Example (cont.)
• Rewrite the code
• Another boundary condition: EOF
• What are other boundary conditions?
s[i] = '\0';
for (i=0; i<MAXLINE-1; i++)
if ((s[i] = getchar()) == '\n' || s[i] == EOF) break;
s[i] = '\0';
This is wrong.
Why?
Trang 13Boundary Testing Example (cont.)
• Rewrite yet again
Where’s the ‘d’?
for (i=0; ; i++) { int c = getchar();
if (c==EOF || c=='\n' || i==MAXLINE-1) {
s[i] = '\0';
break;
} else s[i] = c;
}
Trang 14Ambiguity in Specification
• N u dòng quá dài, x lý th nào? ế ử ế
• Giữ MAXLINE ký tự đầu, bỏ qua phần còn lại?
• Giữ MAXLINE ký tự đầu + ‘\0’, bỏ qua phần còn lại?
• Giữ MAXLINE ký tự đầu+’\0’, lưu phần còn lại cho lần gọi sau của input function?
• Có th ph n ể ầ đặ c t - specification không h ả ề đề ậ c p khi MAXLINE
Trang 16Ki m tra k tr ể đ ướ c và k sau đ
• Xác nh nh ng thu c tính c n i tr đị ữ ộ ầ đ ướ c ( k tr đ ướ c) và sau ( k sau) đ
mã ngu n c thi hành ồ đ
• Ví d : các giá tr ụ ị đầ u vào ph i thu c 1 ph m vi cho tr ả ộ ạ ướ c
double avg( double a[], int n) {
int i; double sum=0.0;
for ( i = 0; i<n; i++)
sum+=a[i];
return sum/n;
}
N u n=0 ?, n u n<0 ? ế ế
Có th thay : return n <=0 ? 0.0: sum/n; ể
Tháng 11/1998, chi n h m Yorktown b chìm : nh p vào giá tr 0, Ct ế ạ ị ậ ị không ki m tra dl nh p d n ể ậ ẫ đế n chia cho 0, và l i làm t u r i lo n, ỗ ầ ố ạ
h th ng ệ ố đẩ y ng ng ho t ư ạ độ ng, tàu chìm !!!
Trang 17Statement Testing
(2) Statement testing
• “Testing để thỏa mãn điều kiện rằng mỗi statement trong 1 CT phải thực hiện ít
nhất trong khi testing.”
‒ Glossary of Computerized System and Software
Development Terminology
Trang 18statement2;
…
if (condition2) statement3;
Trang 19Path Testing
(3) Path testing
• “Kiểm tra để đáp ứng các tiêu chuẩn đảm bảo rằng
mỗi đường dẫn logic xuyên suốt chương trình được
kiểm tra Thường thì đường dẫn xuyên suốt chương
trình này được nhóm thành một tập hữu hạn các lớp Một đường dẫn từ mỗi lớp sau đó được kiểm tra "
‒ Glossary of Computerized System and Software Development Terminology
• Khó h n nhi u so v i statement testing ơ ề ớ
• Với các CT đơn giản, có thể liệt kê các
nhánh đường dẫn xuyên suốt code
• Ngược lại, bằng các đầu vào ngẫu nhiên tạo các đường dẫn theo ct
Trang 20Path Testing Example
• Example pseudocode:
• Đ òi h i 4 t p d li u: ỏ ậ ữ ệ
• condition1 là true và condition2 là true
• condition1 là true và condition2 là false
• condition1 là false và condition2 là true
• condition1 là false và condition2 la false
• Ch ươ ng trình th c t => bùng n các t h p!!! ự ế ổ ổ ợ
if (condition1) statement1;
else
statement2;
…
if (condition2) statement3;
Trang 214 5
Trang 22F B<0T
Trang 23Consider ANOTHER example…
T
F T
T
B<0
Trang 24Stress Testing
(4) Stress testing
• “Tiến hành thử nghiệm để đánh giá một hệ
thống hay thành phần tại hoặc vượt quá các
giới hạn của các yêu cầu cụ thể của nó”
‒ Glossary of Computerized System and Software Development Terminology
• Ph i t o : ả ạ
• Một tập lớn đầu vào - Very large inputs
• Các đầu vào ngẫu nhiên - Random inputs (binary vs ASCII)
• Nên dùng máy tính để ạ đầ t o u vào
Trang 25Stress Testing Example 1
Stress testing: Ph i cung c p ả ấ
random (binary and ASCII)
inputs
Trang 26Stress testing: Ph i cung c p ả ấ
very large inputs
Trang 27Uses of assert
• Typical uses of assert
• Validate formal parameters
• Check for “impossible” logical flow
• Make sure dynamic memory allocation requests worked
assert(ptr != NULL);
size_t Str_getLength(const char *str) { assert(str != NULL);
… }
switch (state) { case START: … break;
case COMMENT: … break;
… default: assert(0); /* Never should get here */ }
Trang 28Internal Testing
• Internal testing: Thi t k CT ế ế để CT t test itself ự
• Internal testing techniques
(1) Kiểm tra bất biến - Testing invariants (2) Kiểm tra các thuộc tính lưu trữ
-Verifying conservation properties (3) Kiểm tra các giá trị trả về -Checking function return values
(4) Tạm thay đổi code -Changing code
temporarily (5) Giữ nguyên mã thử nghiệm -Leaving
testing code intact
Trang 29Testing Invariants
(1) Testing invariants
• Thử nghiệm các đk trước và sau
• Vài khía cạnh của cấu trức dữ liệu không đc thay đổi
• 1 hàm tác động đến cấu trúc dữ liệu phải kiểm tra các bất biến ở đầu và cuối nó
• Ví dụ: Hàm “doubly-linked list insertion”
• Ki m tra ể ở đầ u và cu i ố
• Xoay doubly-linked list
• Khi node x tr ngỏ ượ ạc l i node y, thì li u node y có tr ngệ ỏ ượ ạc l i node x?
• Example: “binary search tree insertion”
function
• Ki m tra ể ở đầ u và cu i ố
• Xoay tree
Trang 30Testing Invariants (cont.)
• Ti n cho vi c dùng ệ ệ assert để test invariants
#ifndef NDEBUG
int isValid (MyType object) {
…
Test invariants here.
Return 1 (TRUE) if object passes
all tests, and 0 (FALSE) otherwise.
assert
Trang 31Ki m tra các thu c tính l u tr ể ộ ư ữ
• Khái quát hóa của testing invariants
• 1 hàm cần kiểm tra các cấu trúc dữ liệu bị tác động tại các điểm đầu và cuối
• T i i m ạ đ ể đầ u, tìm độ dài c a 2 xâu ã cho; tính t ng ủ đ ổ
• T i i m cu i, tìm ạ đ ể ố độ dài c a xâu k t qu ủ ế ả
• 2 độ dài có b ng nhau không ? ằ
-List insertion function
• T i i m kh i ạ đ ể ở đầ u, tính độ dài ds
• T i i m cu i, Tính ạ đ ể ố độ dài m i ớ
• Độ dài m i = ớ độ dài c + 1? ũ
Trang 32• Ph ươ ng th c b phát hi n có l i có th tung ra m t “checked exception” ứ ị ệ ỗ ể ộ
• Ph ươ ng th c tri u g i ph i x lý ngo i l ư ệ ọ ả ử ạ ệ
• Không có c ch x lý exception ơ ế ử
• Hàm phát hi n có l i ch y u thông qua giá tr tr v ệ ỗ ủ ế ị ả ề
• Ng ườ i LT th ườ ng d dàng quên ki m tra GT tr v ễ ể ả ề
• Nói chung là chúng ta nên ki m tra GT tr v ể ả ề
Trang 33Checking Return Values (cont.)
trị đc đọc
ra file và đĩa bị đầy; Hàm này trả
về số ký tự được ghi ( không phải
giá trị)
int i;
if (scanf("%d", &i) != 1) /* Error */
int i = 100;
if (printf("%d", i) != 3) /* Error */
Trang 34T m thay ạ đổ i code
• Tạm thay đổi code để tạo ranh giới nhân tạo
hoặc stress tests
void *testmalloc( size_t n) {
static int count =0;
Trang 35nguyên o n code ki m tra
• C n tr ng v i mâu thu n - conflict: ẩ ọ ớ ẫ
phí bảo trì
thể làm giảm độ rõ ràng của Code !
Trang 36Các chi n l ế ượ c testing
• General testing strategies
(1) Kiểm chứng tăng dần -Testing
Trang 37Testing Incrementally
(1) Testing incrementally
• Thêm tests khi t o 1 l a ch n m i - new cases ạ ự ọ ớ
• Test ph n ầ đơ n gi n tr ả ướ c ph n ph c t p ầ ứ ạ
• Test units (t c là t ng module riêng l ) tr ứ ừ ẻ ướ c khi testing toàn h th ng ệ ố
thử hồi quy
• X lý c 1 l i th ử đ ỗ ườ ng t o ra nh ng l i m i trong 1 he th ng l n, vì v y ạ ữ ỗ ớ ố ớ ậ
…
• Ph i ả đả m b o ch c ch n h th ng không “thoái lui” ki u nh ch c n ng ả ắ ắ ệ ố ể ư ứ ă
tr ướ c kia ang làm vi c gi b broken, nên… đ ệ ờ ị
• Test m i kh n ng ọ ả ă để so sanh phiên b n m i v i phiên b n c ả ớ ớ ả ũ
Trang 38Testing Incrementally (cont.)
(1) Testing incrementally (cont.)
Trang 40Ki m ch ng t ể ứ ự độ ng - Automation
(3) Automation
• Testing thủ công rất nặng nhọc và tốn kém và nhàm chán thậm chí không đủ đọ tin cậy.
• Ba quá trình kiểm chúng bao gồm :
• Tạo testing code
• Vi t 1 b ki m ch ng ế ộ ể ứ để ể ki m tra toàn b ch ộ ươ ng trình m i khi có s thay ỗ ự
i, sau khi biên d ch thành công
• Cần biết cái gì được chờ đợi
• T o ra các ạ đầ u ra, sao cho d dàng nh n bi t là úng hay sai ễ ậ ế đ
• T ự độ ng ki m ch ng có th cung c p: ể ứ ể ấ
• Tốt hơn nhiều so với kiểm chứng thủ công
Trang 41• Ngôn ng scripts : cho phép vi t các o n script ữ ế đ ạ để test tu n t ầ ự
• Unix : có các thao tác trên t p tin nh cmp và diff ệ ư để so sanh d li u xu t, sort s p x p các ữ ệ ấ ắ ế
ph n t , grep ầ ử để ể ki m ch ng d li u xu t, c, sum va freq ứ ữ ệ ấ ư để ttong k t d li u xu t ế ữ ệ ấ
• Khi kiểm chứng lùi, cần đảm bảo phiên bản cũ
là đúng, nếu sai thì rất khó xác định và kết quả sẽ không chính xác
• Cần phải kiểm tra chính việc kiểm chứng lùi 1 cách định kỳ để đảm bảo nó vẫn hợp lệ
Trang 42• T o ra nh ng ki m ch ng ạ ữ ể ứ độ c l p ậ
• Kiểm chứng độc lập với các giá trị nhập và giá trị xuất
mong đợi sẽ bổ xung cho kiểm chứng lùi
• Ví dụ : dùng ngôn ngữ NewAwk thực hiện kiểm chứng 1 ct
ngắn, dữ liệu xuất đc ghi vào 1 tệp tin, kq đúng đc ghi vào
1 tệp khác rồi so sánh 2 tệp, nếu khác nhau thì tbaos lỗi echo 3 5 | newawk ‘{i=1; print ($si)++; print $i ,i}’ > out1
echo ‘3 4 1’ > out2 #két quả đúng
if ! Cmp –s out1 out2 # nếu kq so sánh khác nhau
Trang 43Bug-Driven Testing
(4) Ki m ch ng h ể ứ ướ ng l i : Bug-driven testing ỗ
• Tìm thấy 1 bug => Ngay lập tức tạo 1 test để bắt lỗi
• Đơn giản hóa việc kiểm chứng lùi
(5) Fault injection
• Chủ động (tạm thời) cài các bugs!!!
• Rồi quyết định nếu tìm thấy chúng
• Kiểm chứng bản thân kiểm chứng!!!
Trang 44Ai test cái gì - Who Tests What
• Programmers
• Pro: Người triển khai nắm rõ mọi luồng dữ liệu
• Con: Bị ảnh hưởng bởi cách thức code đc thiết kê/viết
• Quality Assurance (QA) engineers
• Pro: Không có khái niệm về implementation
• Con: Không muốn test mọi logical paths
• Customers
• Field testing
• Pros: Có các cách sử dụng CT bất ngờ;dễ gây lỗi
• Cons: Không đủ trường hợp; khách hàng không
thích tham gia vào quá trình test ;
Trang 45Testing Techniques
các yêu c u - requirements (unit/component ầ
specification, user documentation, v.v.) Còn
c g i là
logic bên trong - internal logic (design, code, v.v.) (Nh ng k t qu mong ư ế ả đợ ẫ đế i v n n t ừ
requirements.) Còn c g i là đ ọ structural testing.
Trang 46Levels or Phases of Testing
• Unit: testing các m u công vi c nh nh t c a LTV ẫ ệ ỏ ấ ủ để có
th l p k ho ch và theo dõi h p lý (vd : function, ể ậ ế ạ ợ
procedure, module, object class, ….)
• Component: testing 1 t p h p các units t o thành 1 ậ ợ ạ
thành ph n (vd : program, package, task, interacting ầ
• Bắt đầu = functional (black-box) tests,
• Rồi thêm = structural (white-box) tests, và
• Tiến hành từ unit level đến system level
với 1 hoặc một vài bước tích hợp
Trang 47T i sao không "test everything"? ạ
•Chi phí cho 'exhaustive' testing:
20 x 4 x 3 x 10 x 2 x 100 = 480,000 tests
•Nếu 1 giây cho 1 test, 8000 phút, 133 giờ, 17.7 ngày
(not counting finger trouble, faults or retest)
nếu 10 secs = 34 wks, 1 min = 4 yrs, 10 min = 40 yrs
Trang 48- Khi b n tin t ạ ưở ng r ng HT ho t ằ ạ độ ng t t ố
- Ph thu c vào risks for your system ụ ộ
Càng ít th i gian, càng nhi u ờ ề để
Th i gian ờ để test luôn có gi i h n ớ ạ
Dùng RISK để xác nh: đị
- Cái gì phải test trước
- Cái gì phải test nhiều
- Mỗi phần tử cần test kỹ như thế nào ? Tức là đâu là trọng tâm
- Cái gì khong cần test (thời điểm này)
Trang 51• Verifying conservation properties
• Checking function return values
• Changing code temporarily
• Leaving testing code intact