ĐẠi học quốc gia hà NỘi trưỜng đẠi học công nghệ Trần Bình Dương sinh ca kiểm thử tham số HÓa cho chưƠng trình java khóa luận tốt nghiệP ĐẠi học hệ chính quy ngành: Công Nghệ Thông Tin



tải về 446.91 Kb.
trang3/10
Chuyển đổi dữ liệu02.09.2016
Kích446.91 Kb.
#31271
1   2   3   4   5   6   7   8   9   10

1.2. Kiểm thử đơn vị


Kiểm thử đơn vị là một cộng việc quan trọng trong kỹ nghệ phần mềm. Kiểm thử đơn vị thường được áp dụng để kiểm tra việc cài đặt của các lớp hoặc phương thức. Để thực hiện việc kiểm thử đơn vị, các lớp kiểm thử được tạo ra. Các lớp kiểm thử này gồm các phương thức kiểm thử. Các phương thức kiểm thử là các phương thức không tham số có kiểu trả về là void chứa trong các lớp kiểm thử để kiểm tra các khía cạnh cài đặt khác nhau của chương trình. Mỗi phương thức kiểm thử trong các lớp kiểm thử biểu thị cho một ca kiểm thử đơn vị (UT).

Có thể chia một phương thức kiểm thử ra làm 3 phần: Các giá trị đầu vào, dãy các lời gọi phương thức, và sự xác nhận (assertions). Kiểm thử thất bại nếu bất cứ sự xác nhận nào bị vị phạm hoặc có một ngoại lệ (exception) xảy ra.

Ví dụ 1.1: Ta xét một phương thức kiểm thử được viết trong nền kiểm thử VSUnit.

public void TestArrayList() {

// exemplary data

int capacity = 1;

object element = null;

// method sequence

ArrayList list = new ArrayList(capacity);

list.Add(element);

// assertions

Assert.IsTrue(list[0] == element);

}

Phương thức kiểm thử TestArrayList bắt đầu bằng việc gán giá trị 1 cho biến capacity và giá trị null cho biến element như là các giá trị đầu vào kiểm thử. Sau đó nó thực hiện một dãy các lời gọi phương thức, trước tiên là khởi tạo một đối tượng ArrayList với kích cỡ là capacity không chứa phần tử nào. ArrayList là một mảng động với kích cỡ có thể thay đổi. Tiếp theo nó chèn một đối tượng là element vào mảng. Và cuối cùng là xác nhận xem phần tử đầu tiên của mảng có bằng đối tượng vừa được chèn vào hay không.



Việc cài đặt nhiều phương thức kiểm thử không đảm bảo rằng sẽ kiểm tra được hết mọi khía cạnh thực thi của chương trình. Với các chương trình có nhiều đường đi thực thi khác nhau thì việc thiếu xót các UT để kiểm tra một vài đường đi thực thi trong chương trình là điều thường xuyên xảy ra. Khi người lập trình thay đổi mã cài đặt của chương trình được kiểm thử thì nếu như các phương thức kiểm thử không được cập nhật theo thì sẽ dẫn đến việc nhiều đường đi thực thi của chương trình sẽ không được kiểm thử.

Các nền kiểm thử hỗ trợ viết các UT theo các cách khác nhau. Tuy nhiên, đa phần các nền kiểm thử đều cung cấp những dịch vụ (service) như sau:

+ Cung cấp thuộc tính để chỉ định các phương thức như là các UT.

+ Phát hiện và thực thi tự động các UT

+ Một runner với khả năng báo cáo (reporting). Một runner có thể là ứng dụng dòng lệnh (console) hoặc là giao diện tích hợp.

Như trong nền kiểm VSUnit[29] cho môi trường .NET. Ta sử dụng thuộc tính [TestClass] để chỉ định một lớp là lớp kiểm thử, và [TestMethod] để chỉ định một phương thức như là một phương thức kiểm thử. Ngoài ra còn có các thuộc tính khác như [ExpectedException] để chỉ định phương thức kiểm thử ném ra ngoại lệ của một kiểu ngoại lệ cụ thể nào đó.

Ví dụ 1.2: Giả sử có một lớp LuhnAlgorithm được cài đặt như sau:

public static class LuhnAlgorithm {



public static bool Validate(string number){

if (number == null)

throw new ArgumentNullException("");

foreach (var c in number)

if (!Char.IsDigit(c))

throw new ArgumentException("");

return false;

}

}



Ta có thể viết một lớp kiểm thử chứa các UT để thực hiện việc kiểm thử lớp LuhnAlgorithm:

[TestClass]// lớp chứa các unit test



public class LuhnAlgorithmTest {

[TestMethod]

[ExpectedException(typeof(ArgumentNullException))]

public void Test1() {

LuhnAlgorithm.Validate(null);

}

[TestMethod]



[ExpectedException(typeof(ArgumentException))]

public void Test2() {

LuhnAlgorithm.Validate("K50");

}

[TestMethod]



public void Test3() {

LuhnAlgorithm.Validate(“123”);

}

}

Khi thực thi phương thức kiểm thử Test1 thì ngoại lệ ArgumentNullException được ném ra. Khi thực thi phương thức kiểm thử Test2 thì ArgumentException được ném ra. Rõ ràng là mỗi phương thức kiểm thử ở trên chỉ có thể kiểm tra việc thực thi của lớp LuhnAlgorithm theo một nhánh đi cụ thể. Thực thi cả 3 phương thức kiểm thử ở trên ta sẽ kiểm tra được tất cả các trường hợp thực thi của lớp LuhnAlgorithm. Với một chương trình có nhiều đường đi thì ta cần viết các UT khác nhau để kiểm tra sự thực thi của chương trình theo các đường đi đó. Tuy nhiên, với những chương trình có nhiều đường đi thực thi khác nhau thì việc viết các UT như thế đòi hỏi nhiều thời gian và công sức để tính các giá trị đầu vào thích hợp và khó có thể kiểm tra hết được sự thực thi của chương trình theo tất cả các đường đi.


1.3. Kiểm thử đơn vị tham số hóa


Có rất nhiều các nền kiểm thử khác nhau như JUnit[33] cho Java, NUnit[34], VSUnit[29] cho .NET để thực thi các ca kiểm thử đơn vị. Tuy nhiên các nền kiểm thử này không hỗ trợ việc sinh tự động các ca kiểm thử đơn vị. Việc viết các ca kiểm thử đơn vị để thực thi tất cả các đường đi của một chương trình là một công việc nặng nhọc. Giải pháp để giảm công sức cho việc này đó là sử dụng ca kiểm thử đơn vị tham số hóa.

Kiểm thử đơn vị tham số hóa[7, 11, 12] là phương pháp mới trong kiểm thử phần mềm. Kiểm thử đơn vị tham số hóa giúp cải thiện nỗ lực trong việc phát triển phần mềm. Về bản chất nó chính là sự mở rộng của phương pháp kiểm thử đơn vị truyền thống.


1.3.1. Khái niệm


Các UT truyền thống là các phương thức kiểm thử không tham số. Ta có thể mở rộng các UT đó bằng cách cho phép truyền vào tham số cho các phương thức kiểm thử. Các ca kiểm thử tham số hóa (PUT) là sự mở rộng của các UT truyền thống. Các PUT là các phương thức kiểm thử cho phép nhận các giá trị đầu vào kiểm thử khác nhau thông qua tham số đầu vào.

PUT được hiểu ở 2 khía cạnh:

+ PUT là sự đặc tả về hành vi bên ngoài của chương trình. Nếu như mỗi UT kiểm tra sự thực thi của chương trình với những giá trị đầu vào được chọn trước và xác nhận kết quả của lần thực thi đó có như mong đợi. Nói cách khác, mỗi UT biểu thị cho một hành vi thực thi cụ thể của chương trình. UT chỉ cung cấp các giá trị đầu vào cụ thể cho chương trình và xác nhận kết quả thực thi của chương trình với những đầu vào cụ thể đó mà không quan tâm tới quá trình thực thi của chương trình với những giá trị đó diễn ra như thế nào. Vì thế, UT biểu thị cho hành vi bên ngoài của chương trình. PUT cũng xác nhận về hành vị thực thi của chương trình nhưng được mở rộng cho tất cả các giá trị đầu vào có thể. Sự xác nhận (assertion) của PUT biểu thị cho các hành vi bên ngoài của chương trình. Ở khía cạnh này, PUT giống như sự đặc tả hộp đen (black-box) cho lớp được PUT kiểm thử.

+ Sự lựa chọn các đầu vào kiểm thử cho PUT dẫn đến việc phân tích chương trình được kiểm thử. Việc phân tích này cần tìm ra các giá trị sao cho khi chương trình được thực thi với các giá trị đó thì có nhiều dòng lệnh được chạy (code coverage)[5]. Nói cách khác, các giá trị cần được lựa chọn sao cho PUT có thể kiểm tra được các đường đi thực thi khác nhau của chương trình. Và mỗi UT có thể được sinh ra từ PUT bằng cách gọi PUT với mỗi đầu vào cụ thể được chọn. Ở khía cạnh này, PUT là kiểm thử hộp trắng (white-box).

Từ đặc tả về PUT, ta có thể phát biểu vấn đề kiểm thử như sau:

Cho một chương trình P gồm các câu lệnh S, cần tính toán một tập hợp các đầu vào (inputs) I sao cho với tất cả các câu lệnh cần thực thi s trong S, tồn tại đầu vào i trong I để P(i) thực thi s.


1.3.2. Mối quan hệ giữa UT và PUT


Với mỗi chương trình có mã nguồn ta có thể viết các PUT để mô tả các hành vi thực thi của nó. Tuy nhiên, nếu đã có các UT được viết thì ta có thể tái cấu trúc mã cài đặt các UT đó để biến chúng thành các PUT. Ngược lại, từ các PUT ta có thể sinh lại các UT bằng cách truyền các giá trị cụ thể làm đầu vào cho PUT. Các nền kiểm thử đơn vị khác nhau hỗ trợ viết các UT theo các cách khác nhau. Do đó các PUT cũng cần được viết sao cho có thể sinh ra các UT tương ứng với các nền kiểm thử đó.

Hình 1: Mối quan hệ giữa UT và PUT

1.3.3. Kiểm thử đơn vị tham số hóa với Pex


Pex[30] là công cụ mạnh mẽ hỗ trợ việc viết và thực thi các ca kiểm thử tham số hóa cho môi trường .NET.

Ví dụ 1.3: Ca kiểm thử tham số hóa sử dụng Pex :

Cũng như với UT, ta có thể viết các lớp kiểm thử chứa các ca kiểm thử tham số hóa. Với sự hỗ trợ của Pex ta có thể thực thi các ca kiểm thử tham số hóa đó. Tuy nhiên không giống việc thực thi các lớp kiểm thử chứa các UT, Pex chỉ thực thi được một ca kiểm thử tham số hóa trong mỗi lần chạy.

[PexMethod] // exemplary data



public void PutArrayList(ArrayList list, object element) {

// assumptions

PexAssume.IsTrue(list != null);

// method sequence



int len = list.Count;

list.Add(element);

// assertions

PexAssert.IsTrue(list[len] == element);

}

Ca kiểm thử tham số hóa ở trên là sự mở rộng của UT trong ví dụ 1.1. Rõ ràng các giá trị đầu vào của UT trong ví dụ 1.1 là các giá trị cụ thể đã được chuyển thành các tham số đầu vào của phương thức. Nếu như UT trong ví dụ 1.1 kiểm thử phương thức Add của lớp ArrayList ở khía cạnh là khi chèn một đối tượng có giá trị null vào một ArrayList rỗng thì đối tượng được chèn vào trở thành phần tử đầu tiên của ArrayList. Thì với ca kiểm thử tham số hóa ở trên phương thức Add được kiểm thử với những đối tượng và ArrayList khác. Các ArrayList làm đầu vào kiểm thử có thể là ArrayList không chứa phần tử nào hoặc ArrayList đã chứa một số phần tử, hoặc ArrayList đã chứa đủ số phần tử so với kích cỡ được cấp phát thì khi chèn một đối tượng object có giá trị là null hay các giá trị khác thì đối tượng được chèn vào trở thành phần tử cuối cùng của ArrayList.



PUT có thể sử dụng các giả thuyết (assumptions) để giảm kích cỡ miền giá trị của tham số đầu vào. Các tham số đầu vào có giá trị thỏa mãn giả thuyết này mới được xem xét làm đầu vào kiểm thử. Như với PUT ở trên thì chỉ các ArrayList khác null mới được lựa chọn làm đầu vào kiểm thử.

Khi Pex thực thi ca kiểm thử tham số hóa ở trên sẽ sinh ra Test Suite gồm 2 VSUnit UT. Đồng thời Pex cũng báo cáo về kết quả xác nhận của ca kiểm thử tham số hóa ở trên.

[TestMethod]

public void TestAddNoOverflow() {

PutArrayList(new ArrayList(1), new object());

}

[TestMethod]



public void TestAddWithOverflow() {

PutArrayList(new ArrayList(0), new object());

}
Với ca kiểm thử tham số hóa này phương thức Add của lớp ArrayList được kiểm thử với tất cả các trường hợp thực thi có thể xảy ra.

Thuộc tính [PexClass] của Pex để xác định một lớp kiểm thử là lớp chứa các ca kiểm thử tham số hóa. Thuộc tính [PexMethod] để chỉ định một phương thức kiểm thử là ca kiểm thử tham số hóa. Ta muốn viết một lớp kiểm thử chứa các ca kiểm thử tham số hóa cần sử dụng thuộc tính [PexClass] và [PexMethod] để viết các ca kiểm thử tham số hóa.


1.3.4. Các mẫu kiểm thử tham số hóa


Viết các ca kiểm thử tham số hóa là một nghệ thuật. Để viết các ca kiểm thử tham số hóa hiệu quả, ta cần thực sự hiểu về mã cài đặt của chương trình mà ta muốn kiểm thử. Pex hỗ trợ nhiều mẫu kiểm thử tham số hóa khác nhau[15]. Các mẫu được sử dụng nhiều nhất đó là mẫu AAA (Triple-A) và AAAA:

+ Với mẫu AAA (Arrange, Act, Assert) PUT được tổ chức thành 3 phần:



      • Arrange: khởi tạo giá trị các biến sẽ sử dụng

      • Act: dãy các lời gọi phương thức

      • Assert: sự xác nhận

+ Với mẫu AAAA, một giả thuyết (Assume) được thêm vào để giới hạn miền giá trị của các tham số đầu vào.

Ví dụ 1.4: Mẫu kiểm thử tham số hóa AAAA

[PexMethod]



void AssumeActAssert(ArrayList list, object item) {

// assume

PexAssume.IsNotNull(list);

// arrange



var count = list.Count;

// act


list.Add(item);

// assert

Assert.IsTrue(list.Count == count + 1);

}

1.3.5. Lựa chọn đầu vào kiểm thử với Pex


Thêm tham số vào UT cải thiện đặc tả về hành vi mong muốn nhưng lại mất đi các ca kiểm thử cụ thể. Ta cần những giá trị thực sự cho các tham số đầu vào để sinh lại các ca kiểm thử cụ thể. PUT sẽ không thể thực thi nếu không có các giá trị cụ thể được truyền vào cho các tham số đầu vào của PUT.

Để có thể sinh các đầu vào cụ thể cho PUT. Pex cần phải phân tích chương trình mà PUT kiểm thử. Có 2 kỹ thuật phân tích chương trình đó là phân tích tĩnh và phân tích động:

+ Phân tích tĩnh (static analysis): Kiểm chứng một tính chất nào đó của chương trình bằng việc phân tích tất cả các đường đi thực thi. Kỹ thuật này coi các cảnh bảo (violations) là các lỗi (error).

+ Phân tích động (dynamic analysis): Kiểm chứng một tính chất bằng việc phân tích một số đường đi thực thi. Đây là một kỹ thuật phân tích động hỗ trợ việc phát hiện ra các lỗi (bugs) nhưng không khẳng định được rằng có còn những lỗi khác hay không. Các kỹ thuật này thường không tìm ra được tất cả các lỗi.

Pex cài đặt một kỹ thuật phân tích chương trình bằng cách kết hợp cả hai kỹ thuật phân tích chương trình ở trên gọi là thực thi tượng trưng động[14, 25]. Về bản chất Pex là một công cụ hỗ trợ kỹ thuật kiểm thử hộp trắng (white-box testing). Tương tự như kỹ thuật phân tích chương trình tĩnh, Pex chứng minh được rằng một tính chất được kiểm chứng trong tất cả các đường đi khả thi. Pex chỉ báo cáo (reporting) về các lỗi thực sự như với kỹ thuật phân tích chương trình động.

Pex sử dụng khả năng của bộ xử lý ràng buộc Z3[31] kết hợp với các lý thuyết toán học khác như hàm chưa định nghĩa, lý thuyết mảng, bit-vetor[2] để giải quyết ràng buộc sinh ra trong quá trình thực thi tượng trưng động và sinh ra các đầu vào kiểm thử cụ thể cho PUT.




tải về 446.91 Kb.

Chia sẻ với bạn bè của bạn:
1   2   3   4   5   6   7   8   9   10




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương