SlideShare a Scribd company logo
UNITTEST &  T EST-DRIVEN DEVELOPMENT AI-T Trainning document Date: 20 th  Feb, 2008
N ội dung Định nghĩa S ử dụng CppUnit T est-Driven Development Hi ệu quả viết UnitTest theo TDD
I.  Định nghĩa S oftware testing UnitTest  ( ProgrammerTest ): test các module (unit) để kiểm tra thiết kế chi tiết của nó là được thực hiện đúng.  IntegrationTest:  test việc ghép nối giữa một nhóm các module SystemTest:  test toàn bộ hệ thống để xem đã đáp ứng được  software requirement PerformanceTest:  kiểm tra các tham số QoS (còn được gọi là  Non-functional requirements ) được đưa ra khi xác đinh yêu cầu của sản phẩm. AcceptanceTest  ( CustomerTest ,  FunctionalTest )  tạo bởi end-user, customer để kiểm tra sản phẩm nhận được
I.  Định nghĩa Unit testing  l à một thủ tục để xác định những module (unit) mã nguồn của phần mềm có hoạt động đúng hay không. In  procedural programming  a unit may be an individual program, function, procedure, etc.,  In  object-oriented programming , the smallest unit is a  method ; which may belong to a base/super class, abstract class or derived/child class.  UnitTest  được thực hiện bởi   developers , ko ph ải bởi  Software testers  ho ặc   end-users .
I.  Định nghĩa L ợi ích của UnitTest Mục đích: phân chia các thành phần của ctrình và đảm bảo các thành phần thực hiện đúng Dễ thay đổi code: programmer yên tâm khi sửa code (refactor) bằng việc test lại để xác định testcase nào bị lỗi    chỉnh sửa kịp thời Dễ tích hợp: các module với interface rõ ràng và được đảm bảo unittest    dễ dàng cho intergrate test Living document: developer có thể dựa vào testcase để biết được hệ thống có unit, hàm gì và sử dụng ntn.
I.  Định nghĩa Hạn chế của UnitTest Không phát hiện được hết các lỗi của ctrình Khi thay đổi interface của module    phải sửa lại nhiều testcase    khi thiết kế testcase cần bỏ đi những code trùng lặp
II. CppUnit Gi ới thiệu : CppUnit : C++ unit testing framework: giúp cho việc test tự động các C++ module (class) (unittest) Được chuyển từ  JUnit (Java) Chạy trên Window/Unix/Solaris S ource: http:// downloads.sourceforge.net/cppunit/cppunit-1.12.1.tar.gz?... Install Window: compile CppUnit project    create cppunit(d).lib for Release/Debug Linux: tar    make    make install
V í dụ: C ần UnitT est cho lớp Money class   Money  { //File: Money.h public : Money ( double amount, std::string currency ) :  m_amount ( amount ) ,  m_currency ( currency ) { } double  getAmount () const { return  m_amount ; } std::string  getCurrency () const { return  m_currency ; } bool  operator   == ( const Money &other ) const { return  m_amount  == other.m_amount  &&  m_currency  == other.m_currency; } bool  operator   != ( const Money &other ) const { return !(*this == other); } Money  &operator   += ( const Money &other ) { if ( m_currency  != other.m_currency) throw IncompatibleMoneyErr(); m_amount  += other.m_amount; return *this; } private : double  m_amount ; std::string  m_currency ; };
II. CppUnit T ừ đặc tả của class Money     C ần test các method của class Test hàm khởi tạo:    testConstructor() Test các phép so sánh: ==, !=     testEqual() Test phép cộng:    testAdd() (cùng loại tiền) và testAddThrow() (ko hợp lệ, ko cùng loại tiền) Từ các testcase trên    xây dựng code để thực hiện test (file  MoneyTest.h ,  MoneyTest.cpp  sử dụng CppUnit library) Thực hiện các testcase (MoneyApp.cpp)
V í dụ: Testsuite cho lớp Money //File  Mon eyTest.h class   MoneyTest  : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(  MoneyTest  ); CPPUNIT_TEST(  testConstructor  ); CPPUNIT_TEST(  testEqual  ); CPPUNIT_TEST(  testAdd  ); CPPUNIT_TEST_EXCEPTION( testAddThrow ,  IncompatibleMoneyErr);  CPPUNIT_TEST_SUITE_END(); public : void  setUp (); void  tearDown (); void  testEqual (); void  testAdd (); void  testAddThrow (); void  testConstructor (); };
V í dụ: Testsuite cho lớp Money //File  MoneyTest.cpp // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION (  MoneyTest  ); void MoneyTest:: setUp () { // Code để khởi tạo các biến, module, … trước khi testsuite được chạy } void MoneyTest:: tearDown () { // Code để giải phóng các biến, module, … sau khi testsuite được chạy xong } void MoneyTest:: testConstructor () { // 1 st  testcase // Set up const std::string currencyFF( "FF" ); const double longNumber = 12345.90; // Process:  hàm khởi tạo Money  money ( longNumber, currencyFF ); // Check:  kết quả của testcase CPPUNIT_ASSERT_EQUAL ( currencyFF, money.getCurrency() ); CPPUNIT_ASSERT_EQUAL ( longNumber+1, money.getAmount() );   //FAIL }
V í dụ: Testsuite cho lớp Money //File  MoneyTest.cpp  (cont…) void  MoneyTest:: testEqual () { // 2 nd  testcase // Set up const Money money123FF( 123, "FF" ); const Money money123USD( 123, "USD" ); const Money money12FF( 12, "FF" ); const Money money12USD( 12, "USD" ); // Process & Check CPPUNIT_ASSERT ( money123FF  ==  money123FF );  // == CPPUNIT_ASSERT ( money12FF  !=  money123FF );  // != amount CPPUNIT_ASSERT ( money123USD  !=  money123FF  );// != currency CPPUNIT_ASSERT ( money12USD != money123FF );  // != currency and != amount }
V í dụ: Testsuite cho lớp Money //File  MoneyTest.cpp  (cont…) void MoneyTest:: testAdd () {   // 3 rd  testcase // Set up const Money money12FF( 12, "FF" ); const Money expectedMoney( 135, "FF" ); // Process Money money( 123, "FF" ); money  +=  money12FF; // Check //  += works CPPUNIT_ASSERT_EQUAL ( expectedMoney.getAmount(), money.getAmount() );  //  += returns ref. on 'this'.   CPPUNIT_ASSERT (&money == &(money += money12FF) ); } void MoneyTest:: testAddThrow () {   // 4 th  testcase // Set up const Money money123FF( 123, "FF" ); // Process Money money( 123, "USD" ); printf("before test"); money  +=  money123FF;  //  should throw an exception printf("after test"); }
V í dụ: Tìm để chạy các testcase //File  MoneyApp.cpp int  main (int argc, char* argv[]) { // Get the top level suite from the registry CppUnit::Test *suite =  CppUnit::TestFactoryRegistry::getRegistry().makeTest(); // Adds the test to the list of test to run CppUnit::TextUi::TestRunner runner; runner.addTest ( suite ); // Change the default outputter to a compiler error format outputter runner.setOutputter ( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); // Run the tests. bool wasSucessful =  runner.run (); // Return error code 1 if the one of test failed. return wasSucessful ? 0 : 1; }
II. CppUnit Configure: VC++ project: link to cppunit.lib and run app when post-compile Linux: compile objects and link with flags: -ldl –lcppunit (có thể c ần   export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH) Note : có thể dùng CppUnit để test C module. Khi đó phải dùng C++ compiler để dịch cho C module. Kết quả test: Linux: chạy file để thực hiện test VC++: tự chạy sau khi dịch (post-compile) hoặc chạy trực tiếp chương trình
V í dụ: Kết quả test (trên Linux và Window đều giống nhau) 1>.F...before test 1>..\..\..\src\MoneyTest.cpp(25) : error : Assertion 1>Test name: MoneyTest:: testConstructor 1>equality assertion failed 1>- Expected: 12346.9 1>- Actual  : 12345.9 1>Failures !!! 1>Run: 4  Failure total: 1  Failures: 1  Errors: 0 II. CppUnit
M ột số macro được sử dụng CPPUNIT_ASSERT(condition) Assertions that a condition is true. CPPUNIT_ASSERT_MESSAGE(message, condition)  Assertion with a user specified message. CPPUNIT_FAIL(message) Fails with the specified message CPPUNIT_ASSERT_EQUAL(expected, actual) Asserts that two values are equals. CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) Asserts that two values are equals, provides additional message on failure  CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)  Macro for primitive value comparisons.  II. CppUnit
Kh ái niệm CppUnit  là ví dụ một framework hỗ trợ cho việc xây dựng unittest Quy tr ình áp dụng cho việc xây dựng unittest cho module: Truyền thống: xây dựng xong module rồi viết unittest TDD: viết test trước rồi viết code song song T est-Driven Development/Design (TDD):  ( Beck 2003 ;  Astels 2003 ), is an evolutionary approach to development which combines  test-first development  where you write a test before you write just enough production code to fulfill that test and  refactoring . III. T est-Driven Development
Y êu cầu: phải hỗ trợ automatic unittest (sử dụng xUnit – unit test framework – ví dụ CppUnit)    cần xác định rõ module requirement trước Test-Driven Development Cycle Add a test Run all tests and see the new one fail Write some Code (for module) Run the automated tests and see them succeed Refactor code Repeat cycle III. T est-Driven Development
Development style principles of "Keep It Simple, Stupid" (KISS)   viết nhưng function của module và code của testcase càng đơn giản càng tốt Y êu cầu programmer “first fail the test cases” để đảm bảo testcase thực sự chạy repeats the steps of adding test cases that fail, passing them, and refactoring     incremental changes   III. T est-Driven Development
Development style III. T est-Driven Development
Ưu điểm Th ời gian viết test thì nhiều, tương đương thời gian code module nhưng sẽ ít hơn thời gian phải debug theo các test truyền thống M ặc dù theo phương pháp này mọi thứ được đơn giản hoá và phát triển dần dần nhưng thực tế vẫn có thể áp dụng cho nhiều hệ thống lớn Đảm bảo hệ thống luôn chạy, luôn hoạt động tại mọi thời điểm    gần như ít phải debug D ễ dàng phát hiện được lỗi (ko đáp ứng đúng requirement) mỗi khi thay đổi code của module L àm nền tảng cho việc thiết kế theo E x treme  P rogramming Nh ược điểm: khó trong một số tình huống như GUI, DB,… mà hệ thống với đầu vào và ra phức tạp không được thiết kế cho việc isolated unit testing và refactoring III. T est-Driven Development
IV. Hi ệu quả viết UnitTest theo TDD Thi ết kế các module để dễ test    dễ với C++ vì module nhỏ nhất là class Lu ôn viết test trước khi viết function của module  TFD -  Test First Development;    T DD=TFD + refactoring Viết testcode và module function dạng empty để tạm thời pass test. Sau đó viết dần dần code cho function (refactor) rỗi lại test ngay    khoảng thời gian giữa 2 hành động này là không quá 10phút    quá trình này phải lặp đi lặp lại N ên viết testcase mới mỗi khi thêm vài dòng code V ới mỗi hàm mới update (ho ặc  clean-up), cần viết ngay testcase và test nhanh nhất có thể . Kh ông nên test 1 chuỗi các hàm của 1 object trong cùng 1 testcase T est trường hợp bình thường, đặc biệt và trường hợp cố tình gây lỗi
IV. Hi ệu quả viết UnitTest theo TDD R efactor (sửa code và bỏ đi những code trùng lặp): cần áp dụng cho cả module function và testcase code    tối ưu và dễ bảo trì Kh ông được xoá và sửa những testcase đã pass C ố gắng viết đủ testcase để test được 100% các dòng code của module (   if, else, …) Nguyên tắc K ISS trong viết UnitTest: trong unittest không nên có if, switch hoặc lệnh so sánh logic vì như thế là ta đã test nhiều trường hợp trong 1 testcase    khó đọc, khó bảo trì, dễ gây bug ngay trong testcase M ỗi 1 class nên có 1 testsuite riêng (ko nên dùng chung cho các class    dễ sang intergrate test)
IV. Hi ệu quả viết UnitTest theo TDD C ác testsuite (file) nên đặt riêng ra, độc lập code với module N ên sử dụng 25-50% thời gian để viết test với lượng code viết testcase khoảng 50% lượng code module C ó thể lấy code của testcase làm example trong tài liệu kỹ thuật của module Sau th ời gian dài, số testcase sẽ nhiều    thời gian chạy lớn    chia ra làm các testcase mới và cũ. Testcase cũ sẽ chạy với tần suất ít hơn Make T est Easy to Run: testcase nên chia làm 2 loại: Lo ại1: đơn giản, ko có yêu cầu đặc biệt để chạy Lo ại2: cần phải thiết lập môi trường hoặc có yêu cầu gì đo Không nên đặt 2 loại trong cung 1 testsuite. Loại 2 nên đặt riêng ra để developer khác khi có thời gian họ sẽ đọc kỹ tài liệu để test loại này
IV. Hi ệu quả viết UnitTest theo TDD Vi ết unittest để dễ bảo trì Kh ông nên test các thành phần private/protected    sử dụng black box hoặc gray box Kh ông nên để code trùng lặp giữa các testcase vì khi thay đổi interface của 1 module function thì lại phải thay đổi hết trong các testcase    kỹ thuật factory: viết riêng function cho đoạn code trùng lặp này C ác testcase không nên phụ thuộc vào nhau cả về data và thứ tự thực hiện. Kh ông được gọi 1 testcase khác trong 1 testcase Kh ông nên có nhiều Assert trong 1 testcase vì khi 1 điều kiện không thảo mãn thì các Assert khác sẽ bị bỏ qua    nên viết thành nhiều testcase riêng
IV. Hi ệu quả viết UnitTest theo TDD Vi ết unittest để dễ đọc, hiểu C ó comment khi Assert (ktra kq test) T ên testcase cần đặt dễ hiểu nhất (có thể tên dài cũng được)    UnitTest như là tài liệu kỹ thuật API của module S ử dụng macro Assert có message đi kèm Trong ph ần init của testsuite, chỉ sử dụng các biến global cũng như khởi tại những object được sử dụng bởi tất cả các testcase. Ko nên tạo biến global mà chỉ sử dụng bởi một số testcase    sử dụng kỹ thuật factory để khắc phục
IV. Hi ệu quả viết UnitTest theo TDD Nh ững điều cần tránh (TDD Anti-Pattern) Ch ỉ test những dữ liệu phù hợp nhất H ạn chế những testcase mà cần phải tạo phức tạp về môi trường    dễ gây khó hiểu, ko biết test cái gì H ạn chế nhiều testcase ko cần thiết    chạy lâu. Kh ông nên viết quá nhiều dòng code cho 1 testcase (ko nên quá 10 dòng) Vi ệc test 100% module    cần hiểu được code bên trong module (white box)    dễ dẫn đến việc phải sửa lại testcase khi refactoring    TDD ko thể dùng với write box mà sử dụng gray box thay thể  C ác testcase có thể bị ảnh hưởng bởi nhau do sử dụng static data trong module Kh ông nên viết tên testcase như test1, test2, … vì khiến cho developer khác phải dựa vào testcase code để biết nó làm gì  Ko n ên tích hợp nhiều testcase vào 1    testcase càng đơn giản càng tôt
IV. Hi ệu quả viết UnitTest theo TDD Kết luận: Th ế nào là một UnitTest tốt Ch ạy nhanh Ch ạy độc lập giữa các testcase (ko phụ thuộc thứ tự test) S ử dụng data dễ đọc, dễ hiểu S ử dụng dữ liệu thực tế có thể T estcase đơn giản, dễ đọc, dễ bảo trì Ph ản ánh đúng hoạt động của module
Tham kh ảo Test Driven Development with Visual Studio 2005 Team System http://www.dotnetjunkies.com/Tutorial/9709CE8B-0986-46D2-AE3B-5989F23D3A0F.dcik Test-driven development http://en.wikipedia.org/wiki/Test-driven_development Unit Test http://en.wikipedia.org/wiki/Unit_testing Instruction to test driven development  http://www.agiledata.org/essays/tdd.html Simple Smalltalk Testing:With Patterns http://www.xprogramming.com/testfram.htm The Three Rules of TDD http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd TTD Anti-pattern http://blog.james-carr.org/?p=44 Unit Testing Tips: Write Maintainable Unit Tests That Will Save You Time And Tears -- MSDN Magazine, January 2006: http://msdn.microsoft.com/msdnmag/issues/06/01/UnitTesting/default.aspx

More Related Content

What's hot (20)

PPTX
Unit Testing And Mocking
Joe Wilson
 
PPT
05 junit
mha4
 
PPTX
Unit testing
princezzlove
 
PDF
Py.test
soasme
 
PPS
Unit Testing
Anuj Arora
 
PPTX
Test-Driven Development
John Blum
 
PPT
01 tester training - overview
song_lachinhminh_smile
 
PPTX
Selenium TestNG
KadarkaraiSelvam
 
PDF
Testing with Spring: An Introduction
Sam Brannen
 
PPTX
Unit Testing with Python
MicroPyramid .
 
PPTX
Introduction to JUnit
Devvrat Shukla
 
PPSX
Junit
FAROOK Samath
 
PDF
Clean Unit Test Patterns
Frank Appel
 
PDF
Page Object Model and Implementation in Selenium
Zoe Gilbert
 
PPTX
Unit testing
Slideshare
 
PDF
Effective testing with pytest
Hector Canto
 
PPTX
Integration testing
Vaibhav Dash
 
PPTX
Unit Testing with xUnit.net - Part 2
BizTalk360
 
ODP
Python unit testing
Darryl Sherman
 
PPS
JUnit Presentation
priya_trivedi
 
Unit Testing And Mocking
Joe Wilson
 
05 junit
mha4
 
Unit testing
princezzlove
 
Py.test
soasme
 
Unit Testing
Anuj Arora
 
Test-Driven Development
John Blum
 
01 tester training - overview
song_lachinhminh_smile
 
Selenium TestNG
KadarkaraiSelvam
 
Testing with Spring: An Introduction
Sam Brannen
 
Unit Testing with Python
MicroPyramid .
 
Introduction to JUnit
Devvrat Shukla
 
Clean Unit Test Patterns
Frank Appel
 
Page Object Model and Implementation in Selenium
Zoe Gilbert
 
Unit testing
Slideshare
 
Effective testing with pytest
Hector Canto
 
Integration testing
Vaibhav Dash
 
Unit Testing with xUnit.net - Part 2
BizTalk360
 
Python unit testing
Darryl Sherman
 
JUnit Presentation
priya_trivedi
 

Similar to Unit Test (20)

PPT
Test Driven development
MU VN
 
PPTX
Automation Testing & TDD
Nhật Nguyễn Khắc
 
DOC
Bai tap testing junit…..
Mua Xuong
 
DOCX
Adp junit
Phong Mai
 
DOCX
Nunit framework for .NET application
Minh Tri Lam
 
PPTX
2014/07/07 Software Testing - Truong Anh Hoang
Vu Hung Nguyen
 
PPTX
TDD (Test Driven Development)
Đông Đô
 
PDF
Cq lt hdt-th2011-02-tuan04
. .
 
PDF
Bai06 kiem tramodule-k-trpm@softtesting-nntu
Jenny Nguyen
 
PDF
Bai06 kiem tramodule-k-trpm@softtesting-nntu
Van Pham
 
PPTX
ĐẢM BẢO CHẤT LƯỢNG PHẦN MỀM
ThanCoi20102202
 
PPTX
Kiểm Thử Junit
Thanh Huong
 
PPTX
BG_Các-loại-kiểm-thử-phần-mềm-cơ bản.pptx
VKit17
 
PPTX
Septeniinternalseminar 20140706softwaretesting-truonganhhoangtalk-final-14070...
Working in Japan
 
PDF
CHUONG 2.pdf
ChauNguyenThiMinh6
 
PPTX
Tdd in action
Kien Nguyen
 
PDF
De bai tap lap trinh lan 1
Informatics and Maths
 
DOCX
Tìm hiểu các kỹ thuật kiểm thử phần mềm ứng dụng trong lập trình Java.
Nguyễn Anh
 
PDF
001-Tong-quan-kiem-thu_thanhDHTL_244.pdf
phamquocthoai7a4
 
PDF
chương03. kiểm thử hộp trắng.pdf
minhchunguyn31
 
Test Driven development
MU VN
 
Automation Testing & TDD
Nhật Nguyễn Khắc
 
Bai tap testing junit…..
Mua Xuong
 
Adp junit
Phong Mai
 
Nunit framework for .NET application
Minh Tri Lam
 
2014/07/07 Software Testing - Truong Anh Hoang
Vu Hung Nguyen
 
TDD (Test Driven Development)
Đông Đô
 
Cq lt hdt-th2011-02-tuan04
. .
 
Bai06 kiem tramodule-k-trpm@softtesting-nntu
Jenny Nguyen
 
Bai06 kiem tramodule-k-trpm@softtesting-nntu
Van Pham
 
ĐẢM BẢO CHẤT LƯỢNG PHẦN MỀM
ThanCoi20102202
 
Kiểm Thử Junit
Thanh Huong
 
BG_Các-loại-kiểm-thử-phần-mềm-cơ bản.pptx
VKit17
 
Septeniinternalseminar 20140706softwaretesting-truonganhhoangtalk-final-14070...
Working in Japan
 
CHUONG 2.pdf
ChauNguyenThiMinh6
 
Tdd in action
Kien Nguyen
 
De bai tap lap trinh lan 1
Informatics and Maths
 
Tìm hiểu các kỹ thuật kiểm thử phần mềm ứng dụng trong lập trình Java.
Nguyễn Anh
 
001-Tong-quan-kiem-thu_thanhDHTL_244.pdf
phamquocthoai7a4
 
chương03. kiểm thử hộp trắng.pdf
minhchunguyn31
 
Ad

Unit Test

  • 1. UNITTEST & T EST-DRIVEN DEVELOPMENT AI-T Trainning document Date: 20 th Feb, 2008
  • 2. N ội dung Định nghĩa S ử dụng CppUnit T est-Driven Development Hi ệu quả viết UnitTest theo TDD
  • 3. I. Định nghĩa S oftware testing UnitTest ( ProgrammerTest ): test các module (unit) để kiểm tra thiết kế chi tiết của nó là được thực hiện đúng. IntegrationTest: test việc ghép nối giữa một nhóm các module SystemTest: test toàn bộ hệ thống để xem đã đáp ứng được software requirement PerformanceTest: kiểm tra các tham số QoS (còn được gọi là Non-functional requirements ) được đưa ra khi xác đinh yêu cầu của sản phẩm. AcceptanceTest ( CustomerTest , FunctionalTest ) tạo bởi end-user, customer để kiểm tra sản phẩm nhận được
  • 4. I. Định nghĩa Unit testing l à một thủ tục để xác định những module (unit) mã nguồn của phần mềm có hoạt động đúng hay không. In procedural programming a unit may be an individual program, function, procedure, etc., In object-oriented programming , the smallest unit is a method ; which may belong to a base/super class, abstract class or derived/child class. UnitTest được thực hiện bởi developers , ko ph ải bởi Software testers ho ặc end-users .
  • 5. I. Định nghĩa L ợi ích của UnitTest Mục đích: phân chia các thành phần của ctrình và đảm bảo các thành phần thực hiện đúng Dễ thay đổi code: programmer yên tâm khi sửa code (refactor) bằng việc test lại để xác định testcase nào bị lỗi  chỉnh sửa kịp thời Dễ tích hợp: các module với interface rõ ràng và được đảm bảo unittest  dễ dàng cho intergrate test Living document: developer có thể dựa vào testcase để biết được hệ thống có unit, hàm gì và sử dụng ntn.
  • 6. I. Định nghĩa Hạn chế của UnitTest Không phát hiện được hết các lỗi của ctrình Khi thay đổi interface của module  phải sửa lại nhiều testcase  khi thiết kế testcase cần bỏ đi những code trùng lặp
  • 7. II. CppUnit Gi ới thiệu : CppUnit : C++ unit testing framework: giúp cho việc test tự động các C++ module (class) (unittest) Được chuyển từ JUnit (Java) Chạy trên Window/Unix/Solaris S ource: http:// downloads.sourceforge.net/cppunit/cppunit-1.12.1.tar.gz?... Install Window: compile CppUnit project  create cppunit(d).lib for Release/Debug Linux: tar  make  make install
  • 8. V í dụ: C ần UnitT est cho lớp Money class Money { //File: Money.h public : Money ( double amount, std::string currency ) : m_amount ( amount ) , m_currency ( currency ) { } double getAmount () const { return m_amount ; } std::string getCurrency () const { return m_currency ; } bool operator == ( const Money &other ) const { return m_amount == other.m_amount && m_currency == other.m_currency; } bool operator != ( const Money &other ) const { return !(*this == other); } Money &operator += ( const Money &other ) { if ( m_currency != other.m_currency) throw IncompatibleMoneyErr(); m_amount += other.m_amount; return *this; } private : double m_amount ; std::string m_currency ; };
  • 9. II. CppUnit T ừ đặc tả của class Money  C ần test các method của class Test hàm khởi tạo:  testConstructor() Test các phép so sánh: ==, !=  testEqual() Test phép cộng:  testAdd() (cùng loại tiền) và testAddThrow() (ko hợp lệ, ko cùng loại tiền) Từ các testcase trên  xây dựng code để thực hiện test (file MoneyTest.h , MoneyTest.cpp sử dụng CppUnit library) Thực hiện các testcase (MoneyApp.cpp)
  • 10. V í dụ: Testsuite cho lớp Money //File Mon eyTest.h class MoneyTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MoneyTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testEqual ); CPPUNIT_TEST( testAdd ); CPPUNIT_TEST_EXCEPTION( testAddThrow , IncompatibleMoneyErr); CPPUNIT_TEST_SUITE_END(); public : void setUp (); void tearDown (); void testEqual (); void testAdd (); void testAddThrow (); void testConstructor (); };
  • 11. V í dụ: Testsuite cho lớp Money //File MoneyTest.cpp // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION ( MoneyTest ); void MoneyTest:: setUp () { // Code để khởi tạo các biến, module, … trước khi testsuite được chạy } void MoneyTest:: tearDown () { // Code để giải phóng các biến, module, … sau khi testsuite được chạy xong } void MoneyTest:: testConstructor () { // 1 st testcase // Set up const std::string currencyFF( "FF" ); const double longNumber = 12345.90; // Process: hàm khởi tạo Money money ( longNumber, currencyFF ); // Check: kết quả của testcase CPPUNIT_ASSERT_EQUAL ( currencyFF, money.getCurrency() ); CPPUNIT_ASSERT_EQUAL ( longNumber+1, money.getAmount() ); //FAIL }
  • 12. V í dụ: Testsuite cho lớp Money //File MoneyTest.cpp (cont…) void MoneyTest:: testEqual () { // 2 nd testcase // Set up const Money money123FF( 123, "FF" ); const Money money123USD( 123, "USD" ); const Money money12FF( 12, "FF" ); const Money money12USD( 12, "USD" ); // Process & Check CPPUNIT_ASSERT ( money123FF == money123FF ); // == CPPUNIT_ASSERT ( money12FF != money123FF ); // != amount CPPUNIT_ASSERT ( money123USD != money123FF );// != currency CPPUNIT_ASSERT ( money12USD != money123FF ); // != currency and != amount }
  • 13. V í dụ: Testsuite cho lớp Money //File MoneyTest.cpp (cont…) void MoneyTest:: testAdd () { // 3 rd testcase // Set up const Money money12FF( 12, "FF" ); const Money expectedMoney( 135, "FF" ); // Process Money money( 123, "FF" ); money += money12FF; // Check // += works CPPUNIT_ASSERT_EQUAL ( expectedMoney.getAmount(), money.getAmount() ); // += returns ref. on 'this'. CPPUNIT_ASSERT (&money == &(money += money12FF) ); } void MoneyTest:: testAddThrow () { // 4 th testcase // Set up const Money money123FF( 123, "FF" ); // Process Money money( 123, "USD" ); printf("before test"); money += money123FF; // should throw an exception printf("after test"); }
  • 14. V í dụ: Tìm để chạy các testcase //File MoneyApp.cpp int main (int argc, char* argv[]) { // Get the top level suite from the registry CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); // Adds the test to the list of test to run CppUnit::TextUi::TestRunner runner; runner.addTest ( suite ); // Change the default outputter to a compiler error format outputter runner.setOutputter ( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); // Run the tests. bool wasSucessful = runner.run (); // Return error code 1 if the one of test failed. return wasSucessful ? 0 : 1; }
  • 15. II. CppUnit Configure: VC++ project: link to cppunit.lib and run app when post-compile Linux: compile objects and link with flags: -ldl –lcppunit (có thể c ần export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH) Note : có thể dùng CppUnit để test C module. Khi đó phải dùng C++ compiler để dịch cho C module. Kết quả test: Linux: chạy file để thực hiện test VC++: tự chạy sau khi dịch (post-compile) hoặc chạy trực tiếp chương trình
  • 16. V í dụ: Kết quả test (trên Linux và Window đều giống nhau) 1>.F...before test 1>..\..\..\src\MoneyTest.cpp(25) : error : Assertion 1>Test name: MoneyTest:: testConstructor 1>equality assertion failed 1>- Expected: 12346.9 1>- Actual : 12345.9 1>Failures !!! 1>Run: 4 Failure total: 1 Failures: 1 Errors: 0 II. CppUnit
  • 17. M ột số macro được sử dụng CPPUNIT_ASSERT(condition) Assertions that a condition is true. CPPUNIT_ASSERT_MESSAGE(message, condition) Assertion with a user specified message. CPPUNIT_FAIL(message) Fails with the specified message CPPUNIT_ASSERT_EQUAL(expected, actual) Asserts that two values are equals. CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) Asserts that two values are equals, provides additional message on failure CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) Macro for primitive value comparisons. II. CppUnit
  • 18. Kh ái niệm CppUnit là ví dụ một framework hỗ trợ cho việc xây dựng unittest Quy tr ình áp dụng cho việc xây dựng unittest cho module: Truyền thống: xây dựng xong module rồi viết unittest TDD: viết test trước rồi viết code song song T est-Driven Development/Design (TDD): ( Beck 2003 ; Astels 2003 ), is an evolutionary approach to development which combines test-first development where you write a test before you write just enough production code to fulfill that test and refactoring . III. T est-Driven Development
  • 19. Y êu cầu: phải hỗ trợ automatic unittest (sử dụng xUnit – unit test framework – ví dụ CppUnit)  cần xác định rõ module requirement trước Test-Driven Development Cycle Add a test Run all tests and see the new one fail Write some Code (for module) Run the automated tests and see them succeed Refactor code Repeat cycle III. T est-Driven Development
  • 20. Development style principles of "Keep It Simple, Stupid" (KISS)  viết nhưng function của module và code của testcase càng đơn giản càng tốt Y êu cầu programmer “first fail the test cases” để đảm bảo testcase thực sự chạy repeats the steps of adding test cases that fail, passing them, and refactoring  incremental changes III. T est-Driven Development
  • 21. Development style III. T est-Driven Development
  • 22. Ưu điểm Th ời gian viết test thì nhiều, tương đương thời gian code module nhưng sẽ ít hơn thời gian phải debug theo các test truyền thống M ặc dù theo phương pháp này mọi thứ được đơn giản hoá và phát triển dần dần nhưng thực tế vẫn có thể áp dụng cho nhiều hệ thống lớn Đảm bảo hệ thống luôn chạy, luôn hoạt động tại mọi thời điểm  gần như ít phải debug D ễ dàng phát hiện được lỗi (ko đáp ứng đúng requirement) mỗi khi thay đổi code của module L àm nền tảng cho việc thiết kế theo E x treme P rogramming Nh ược điểm: khó trong một số tình huống như GUI, DB,… mà hệ thống với đầu vào và ra phức tạp không được thiết kế cho việc isolated unit testing và refactoring III. T est-Driven Development
  • 23. IV. Hi ệu quả viết UnitTest theo TDD Thi ết kế các module để dễ test  dễ với C++ vì module nhỏ nhất là class Lu ôn viết test trước khi viết function của module TFD - Test First Development; T DD=TFD + refactoring Viết testcode và module function dạng empty để tạm thời pass test. Sau đó viết dần dần code cho function (refactor) rỗi lại test ngay  khoảng thời gian giữa 2 hành động này là không quá 10phút  quá trình này phải lặp đi lặp lại N ên viết testcase mới mỗi khi thêm vài dòng code V ới mỗi hàm mới update (ho ặc clean-up), cần viết ngay testcase và test nhanh nhất có thể . Kh ông nên test 1 chuỗi các hàm của 1 object trong cùng 1 testcase T est trường hợp bình thường, đặc biệt và trường hợp cố tình gây lỗi
  • 24. IV. Hi ệu quả viết UnitTest theo TDD R efactor (sửa code và bỏ đi những code trùng lặp): cần áp dụng cho cả module function và testcase code  tối ưu và dễ bảo trì Kh ông được xoá và sửa những testcase đã pass C ố gắng viết đủ testcase để test được 100% các dòng code của module (  if, else, …) Nguyên tắc K ISS trong viết UnitTest: trong unittest không nên có if, switch hoặc lệnh so sánh logic vì như thế là ta đã test nhiều trường hợp trong 1 testcase  khó đọc, khó bảo trì, dễ gây bug ngay trong testcase M ỗi 1 class nên có 1 testsuite riêng (ko nên dùng chung cho các class  dễ sang intergrate test)
  • 25. IV. Hi ệu quả viết UnitTest theo TDD C ác testsuite (file) nên đặt riêng ra, độc lập code với module N ên sử dụng 25-50% thời gian để viết test với lượng code viết testcase khoảng 50% lượng code module C ó thể lấy code của testcase làm example trong tài liệu kỹ thuật của module Sau th ời gian dài, số testcase sẽ nhiều  thời gian chạy lớn  chia ra làm các testcase mới và cũ. Testcase cũ sẽ chạy với tần suất ít hơn Make T est Easy to Run: testcase nên chia làm 2 loại: Lo ại1: đơn giản, ko có yêu cầu đặc biệt để chạy Lo ại2: cần phải thiết lập môi trường hoặc có yêu cầu gì đo Không nên đặt 2 loại trong cung 1 testsuite. Loại 2 nên đặt riêng ra để developer khác khi có thời gian họ sẽ đọc kỹ tài liệu để test loại này
  • 26. IV. Hi ệu quả viết UnitTest theo TDD Vi ết unittest để dễ bảo trì Kh ông nên test các thành phần private/protected  sử dụng black box hoặc gray box Kh ông nên để code trùng lặp giữa các testcase vì khi thay đổi interface của 1 module function thì lại phải thay đổi hết trong các testcase  kỹ thuật factory: viết riêng function cho đoạn code trùng lặp này C ác testcase không nên phụ thuộc vào nhau cả về data và thứ tự thực hiện. Kh ông được gọi 1 testcase khác trong 1 testcase Kh ông nên có nhiều Assert trong 1 testcase vì khi 1 điều kiện không thảo mãn thì các Assert khác sẽ bị bỏ qua  nên viết thành nhiều testcase riêng
  • 27. IV. Hi ệu quả viết UnitTest theo TDD Vi ết unittest để dễ đọc, hiểu C ó comment khi Assert (ktra kq test) T ên testcase cần đặt dễ hiểu nhất (có thể tên dài cũng được)  UnitTest như là tài liệu kỹ thuật API của module S ử dụng macro Assert có message đi kèm Trong ph ần init của testsuite, chỉ sử dụng các biến global cũng như khởi tại những object được sử dụng bởi tất cả các testcase. Ko nên tạo biến global mà chỉ sử dụng bởi một số testcase  sử dụng kỹ thuật factory để khắc phục
  • 28. IV. Hi ệu quả viết UnitTest theo TDD Nh ững điều cần tránh (TDD Anti-Pattern) Ch ỉ test những dữ liệu phù hợp nhất H ạn chế những testcase mà cần phải tạo phức tạp về môi trường  dễ gây khó hiểu, ko biết test cái gì H ạn chế nhiều testcase ko cần thiết  chạy lâu. Kh ông nên viết quá nhiều dòng code cho 1 testcase (ko nên quá 10 dòng) Vi ệc test 100% module  cần hiểu được code bên trong module (white box)  dễ dẫn đến việc phải sửa lại testcase khi refactoring  TDD ko thể dùng với write box mà sử dụng gray box thay thể C ác testcase có thể bị ảnh hưởng bởi nhau do sử dụng static data trong module Kh ông nên viết tên testcase như test1, test2, … vì khiến cho developer khác phải dựa vào testcase code để biết nó làm gì Ko n ên tích hợp nhiều testcase vào 1  testcase càng đơn giản càng tôt
  • 29. IV. Hi ệu quả viết UnitTest theo TDD Kết luận: Th ế nào là một UnitTest tốt Ch ạy nhanh Ch ạy độc lập giữa các testcase (ko phụ thuộc thứ tự test) S ử dụng data dễ đọc, dễ hiểu S ử dụng dữ liệu thực tế có thể T estcase đơn giản, dễ đọc, dễ bảo trì Ph ản ánh đúng hoạt động của module
  • 30. Tham kh ảo Test Driven Development with Visual Studio 2005 Team System http://www.dotnetjunkies.com/Tutorial/9709CE8B-0986-46D2-AE3B-5989F23D3A0F.dcik Test-driven development http://en.wikipedia.org/wiki/Test-driven_development Unit Test http://en.wikipedia.org/wiki/Unit_testing Instruction to test driven development http://www.agiledata.org/essays/tdd.html Simple Smalltalk Testing:With Patterns http://www.xprogramming.com/testfram.htm The Three Rules of TDD http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd TTD Anti-pattern http://blog.james-carr.org/?p=44 Unit Testing Tips: Write Maintainable Unit Tests That Will Save You Time And Tears -- MSDN Magazine, January 2006: http://msdn.microsoft.com/msdnmag/issues/06/01/UnitTesting/default.aspx