Sinh tự động các ca kiểm thử bằng thực thi ký hiệu

Một phần của tài liệu Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh (Trang 75)

Đối với ví dụ về thẻ ATM, để sinh tự động các ca kiểm thử cho phương thức withdrawMoney() thì tham số của nó là có dạng ký hiệu. Do các điều kiện về số lượng rút trong ngày và số dư tài khoản khác nhau đối với các loại thẻ nên chúng ta tiến hành nạp chồng phương thức withdrawMoney() tại các lớp SilverATM và GoldATM. Sau đó sử dụng thực thi ký hiệu của JPF mở rộng để sinh các ca kiểm thử cho phương thức withdrawMoney().

Do hai thuộc tính balanceAmount và withdrawalAmountPerDay tham gia vào quá trình sinh ca kiểm thử nên chúng phải được khai báo có dạng ký hiệu để được sinh giá trị khởi tạo trong các ca kiểm thử. Để khai báo một thuộc tính là ký hiệu thì chúng ta chỉ cần thêm dòng khai báo @Symbolic("true") ngay phía trên dòng khai báo thuộc tính.

Vì số tiền có thể rút mỗi lần đối với các loại thẻ phải lớn hơn 0 nên phương thức withdrawMoney() của các lớp ATMcard, SilverATM và GoldATM được viết lại cho thực thi ký hiệu để sinh các ca kiểm thử như sau:

class ATMcard {

@Symbolic("true") //Khai báo thuộc tính là ký hiệu public int withdrawalAmountPerDay;

@Symbolic("true") //Khai báo thuộc tính là ký hiệu public int balanceAmount;

...

public void withdrawMoney(int amount) {

if(amount>0) {

if(withdrawalAmountPerDay+amount <=2000)

withdrawalAmountPerDay += amount;

balanceAmount -= amount;

}

} ... }

Do JPF không nhận diện được các thuộc tính được thừa kế ở lớp con là ký hiệu nên chúng ta phải khai báo nạp chồng chúng ở lớp con.

class SilverATM extends ATMcard {

@Symbolic("true") //Khai báo thuộc tính là ký hiệu public int withdrawalAmountPerDay;

@Symbolic("true") //Khai báo thuộc tính là ký hiệu public int balanceAmount;

...

public void withdrawMoney(int amount) {

if(amount>0) { if(withdrawalAmountPerDay+amount<=3000) withdrawalAmountPerDay += amount; if(balanceAmount-amount >= -5000) balanceAmount -= amount; } } ... }

class GoldATM extends SilverATM {

@Symbolic("true") //Khai báo thuộc tính là ký hiệu public int withdrawalAmountPerDay;

@Symbolic("true") //Khai báo thuộc tính là ký hiệu public int balanceAmount;

...

public void withdrawMoney(int amount) {

if(amount>0) {

withdrawalAmountPerDay += amount; if(balanceAmount-amount >= -10000) balanceAmount -= amount; } } ... }

Phương thức withdrawMoney() cần được gọi bởi một trình điều khiển nào đó. Trình điều khiển có thể nằm trong một lớp điều khiển riêng hoặc nằm ngay trong phương thức main() của một trong các lớp của bạn. Để đơn giản, chúng ta sẽ viết trình điều khiển trong một lớp Test có chưa phương thức main().

Trong ví dụ này, trình điều khiển phải gọi đến phương thức withdrawMoney() của cả ba lớp ATMcard, SilverATM và GoldATM với đúng số lượng và kiểu của các tham số. Để cho phương thức main() đơn giản, các khai báo đối tượng và các lời gọi đến phương thức withdrawMoney() của các đối tượng được tạo ra được đặt trong một hàm riêng biệt có tên là testDriver(). Trong phương thức main(), sau lời gọi phương thức testDriver mới được tạo ra là lệnh in các điều kiện dẫn (Path Condition). Khi phương thức withdrawMoney() được thực thi ký hiệu thì bất kỳ giá trị cụ thể nào được chuyển cho phương thức đều sẽ được thay thế bằng các giá trị ký hiệu.

Hiện tại cách nhanh nhất để nhìn thấy các ca kiểm thử là việc in ra các điều kiện dẫn bằng việc gọi gov.nasa.jpf.symbc.Debug.printPC(). (adsbygoogle = window.adsbygoogle || []).push({});

import gov.nasa.jpf.symbc.Debug; import gov.nasa.jpf.jvm.Verify;

public class Test {

public static void testDriver(){

ATMcard c=new ATMcard (1,2);

SilverATM s = new SilverATM(1,2,0);

GoldATM g=new GoldATM(1,2,0,0);

Verify.beginAtomic(); switch (Verify.random(2)){ case 0: c.withdrawMoney(1); break; case 1:

s.withdrawMoney(2); break; case 2: g.withdrawMoney(3); break; } Verify.endAtomic(); }

public static void main(String args[]) {

testDriver();

Debug.printPC("Path Condition: "); }

}

Để thực hiện sinh các ca kiểm thử tự động, ta phải sửa tham số chạy của JPF trong Eclipse như sau:

+vm.insn_factory.class=gov.nasa.jpf.symbc.SymbolicInstructionFactory +jpf.listener=gov.nasa.jpf.symbc.SymbolicListener +symbolic.method=withdrawMoney(sym) +search.multiple_errors=true +jpf.report.console.finished= Test

Sau khi cho JPF thực hiện chương trình, các ca kiểm thử được sinh ra bao gồm cả số tiền cần rút là số âm. Chúng ta có thể hạn chế miền giá trị các ca kiểm thử bằng cách dùng phương thức Verify.ignoreIf() để ép quay lui nếu điều kiện truyền vào hàm ignoreIf() thỏa mãn. Trong bài toán trên, để loại bỏ các ca kiểm thử với số tiền mỗi lần rút nhỏ hơn hoặc bằng 0, ta thêm lệnh Verify.ignoreIf(amount <= 0) vào phương thức withdrawMoney() trước tất cả các lệnh. Ví dụ phương thức withdrawMoney() của lớp ATMcard sẽ như sau:

public void withdrawMoney(long amount) { Verify.ignoreIf(amount<=0);

if(withdrawalAmountPerDay+amount <= 2000) withdrawalAmountPerDay += amount; if(balanceAmount-amount >=0) balanceAmount -= amount; } }

Ta chèn lệnh Verify.ignoreIf(amount<=0) vào vị trí tương tự trong phương thức withdrawMoney() của các lớp SilverATM và GoldATM.

Một phần của tài liệu Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh (Trang 75)