Bài giảng Kỹ thuật lập trình - Chương 6: Testing - Vũ Đức Vượng

•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).

ppt 52 trang xuanthi 27/12/2022 2980
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 6: Testing - Vũ Đức Vượng", để tải tài liệu gốc về máy hãy click vào nút Download ở trên.

File đính kèm:

  • pptbai_giang_ky_thuat_lap_trinh_chuong_6_testing_vu_duc_vuong.ppt

Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 6: Testing - Vũ Đức Vượng

  1. Mục đích • Giúp hiểu về: • Internal testing • External testing • General testing strategies • Vì sao? • Khó có thể khẳng định 1 CT lớn có làm việc chuẩn hay không • 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 2
  2. Khá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ó. • Myers: Là quá trình thực hiện 1 CT với mục đích tìm ra những lỗi. • IEEE: Là quá trình kiểm tra hay đánh giá 1 hệ thống hay 1 thành phần hệ thống một cách thủ công hay tự động để kiểm chứng rằng nó thỏa mãn những yêu cầu đặc thù hoặc để xác định sự khác biệt giữa kết quả mong đợi và kết quả thực tế 4
  3. Program Testing • Thực dụng: Thuyết phục bản thân rằng CT có thể làm việc Specification Testing Probably Right/Wrong program.c Strategy 6
  4. External 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 8
  5. Boundary Testing Example • VD : đọc 1 dòng từ stdin và đưa vào mảng ký tự int i; char s[MAXLINE]; for (i=0; (s[i]=getchar()) != '\n' && i 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] 10
  6. Boundary Testing Example (cont.) • Rewrite the code int i; char s[MAXLINE]; for (i=0; i<MAXLINE-1; i++) if ((s[i] = getchar()) == '\n') break; s[i] = '\0'; • Another boundary condition: EOF for (i=0; i<MAXLINE-1; i++) if ((s[i] = getchar()) == '\n' || s[i] == EOF) break; s[i] = '\0'; • What are other boundary conditions? • Nearly full This is wrong. • Exactly full Why? • Over full 12
  7. Ambiguity 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 bị quá • Có thể người ta không muốn dòng dài quá giới hạn trong mọi trường hợp • Đạo đức: kiểm tra đã phát hiện ra một vấn đề thiết kế, thậm chí có thể là một vấn đề đặc điểm kỹ thuật ! • Quyết định phải làm gì • Cắt những dòng quá dài? • Lưu phần còn lại để đọc như 1 dòng mới? 14
  8. Kiể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 !!! 16
  9. Statement Testing Example • Example pseudocode: if (condition1) statement1; else statement2; Statement testing: if (condition2) Phải chắc chắn cả lệnh “if” và statement3; 4 lệnh lồng phải đc thực hiện else statement4; • Đòi hỏi 2 tập dữ liệu;vd: • condition1 là đúng và condition2 là đúng • Thực hiện statement1 và statement3 • condition1 là sai và condition2 là sai • Thực hiện statement2 và statement4 18
  10. Path Testing Example • Example pseudocode: if (condition1) statement1; else statement2; Path testing: if (condition2) Cần đảm bảo tất cả các statement3; đường dẫn được thực hiện else statement4; • Đò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!!! 20
  11. Consider ANOTHER example (1) input(A,B) if (A>B) then 1 (2) B := B*B A>B end_if T if (B ? (A>B) Л (B<0) 22
  12. Stress 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 24
  13. Stress Testing Example 2 • Example program: #include int main(void) { short charCount = 0; Stress testing: Phải cung cấp while (getchar() != EOF) very large inputs charCount++; printf("%hd\n", charCount); return 0; } • Mục tiêu: Đếm và in số các kỹ tự trong stdin • Làm việc với tập dữ lieuj có kích thước phù hợp • Sẽ có lỗi với tập dữ liệu do máy tạo chứa hơn 32767 characters 26
  14. Internal 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 28
  15. Testing 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. Có thể dùng NDEBUG } #endif trong code, giống như assert void myFunction(MyType object) { assert(isValid(object)); Manipulate object here. assert(isValid(object)); } 30
  16. Kiểm tra GT trả về Checking Return Values • Trong Java và C++: • 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ệ • Trong C: • 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ề 32
  17. Tạm thay đổi code • Tạm thay đổi code để tạo ranh giới nhân tạo hoặc stress tests • VD: CT sắp xếp trên mảng • Tạm đặt kích thước mảng nhỏ • CT có xử lý tràn số hay không ? • Viết 1 phiên bản hàm cấp phát bộ nhớ và phát hiện ra lỗi sớm, để kiểm chứng đoạn mã nguồn bị lỗi thiếu bộ nhớ : void *testmalloc( size_t n) { static int count =0; if (++count . 10) return NULL; else return malloc(n); } 34
  18. Các chiến lược testing • General testing strategies (1) Kiểm chứng tăng dần -Testing incrementally (2) So sanh các cài đặt -Comparing implementations (3) Kiểm chứng tự động - Automation (4) Bug-driven testing (5) Tiêm, gài lỗi - Fault injection 36
  19. Testing Incrementally (cont.) (1) Testing incrementally (cont.) • Tạo “giàn giáo” - scaffolds và “mẫu” -stubs để test đoạn code mà ta quan tâm Scaffold: Đoạn code •Hàm gọi đến code tạm thời gọi đến code mà ta quan tâm Mà ta quan tâm Đoạn code cần quan tâm Stub: Đoạn code Hàm được gọi Hàm được gọi Tạm thời được gọi bởi đoạn code cần •bởi đoạn code cần Bởi đoạn code cần quan tâm •quan tâm Quan tâm 38
  20. Kiể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 : • Thực hiện kiểm chứng nhiều lần • Dùng nhiều bộ dữ liệu nhập • Nhiều lần so sánh dữ liệu xuất • vì vậy cần kiểm chứng = chương trình để : tránh mệt mỏi, giảm sự bất cẩn • 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 40
  21. • 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 then echo ‘BAD: test failed’ Fi • Mọt lỗi có thể cần nhiều thao tác kiểm chứng hoặc phải kiểm tra toàn bộ các lợp mới, hoặc có thể thêm vào những đoạn Ct bảo vệ để có thể bắt đc những lỗi trong CT 42
  22. Ai test cái gì - Who Tests What • Programmers • White-box testing • 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 • Black-box testing • 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 ; 44
  23. Levels 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 object classes, ) • Product: testing các thành phần tạo thành 1 sản phẩm ( subsystem, application, ) • System: testing toàn bộ hệ thống • Testing thường: • 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 46
  24. Bao nhiêu testing là đủ? - Không bao giờ đủ ! - Khi bạn thực hiện những test mà bạn đã lên kế hoạch - Khi khách hàng/người sử dụng thấy thỏa mãn - Khi bạn đã chứng minh đc rằng hệ thống hoạt động đúng, chính xác - 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) 48
  25. The testing paradox • Mục đích của testing: để tìm ra lỗi • Tìm thấy lỗi làm mất (hủy hoại) tự tin - confidence => Mục đích của testing: hủy hoại sự tự tin • Nhưng mục đích của testing: Xây dựng niềm tin, tự tin => Cách tốt nhất để xây dựng niềm tin là : Cố gắng hủy hoại nó 50
  26. Summary (cont.) • General testing strategies • Testing incrementally • Regression testing • Scaffolds and stubs • Automation • Comparing independent implementations • Bug-driven testing • Fault injection • Test the code, the tests – and the specification! • Kiểm chứng code, kiểm chứng việc kiểm chứng – và kiểm chứng cả đặc tả ! 52