Kiểm thử demo bằng NModel

Một phần của tài liệu Nghiên cứu ứng dụng “NModel” trong việc phát triển hệ thống nhúng thời gian thực (Trang 57)

4.2.2.1. Kiểm thử ngoại tuyến (Offline)

Quy trình kiểm thử chƣơng trình bằng NModel thông qua các bƣớc sau: xây dựng implementation, viết MP, sử dụng mpv để hình dung và phân tích, sử dụng otg để sinh bộ kiểm thử tự động, cuối cùng là sử dụng công cụ ct để chạy một bộ kiểm thử. Bƣớc đầu tiên là xây dựng hai MP đầu vào từ thực hiện (implementation) client/server đã đƣợc xây dựng, đó là MP hợp đồng ClientServer (M1) và MP kịch bản (M2):

MP ClientServer M1:

Mục đích của M1: là biểu diễn hệ thống phân tán với các chƣơng trình chạy trên hai máy tính đƣợc kết nối mạng. Client và Server thực hiện trong một chủ để duy nhất, đan xen các cuộc gọi phƣơng thức của chúng theo một trật tự phù hợp với giao thức của chúng (hình 4.2). Tự động sinh và kiểm chứng các test run.

Các hành động: Các hành động của client và server là riêng biệt. Việc gửi và nhận của client không giống với việc gửi và nhận của server. Do đó, các hành động bao gồm: ClientSend, ServerSend, ClientReceive, và ServerReceive.

Các biến trạng thái: Trong ví dụ này, có hai loại ràng buộc theo trình tự đó là: Socket phải đƣợc tạo (Created), đƣợc kết nối (Connected), và đóng theo giao thức. Các hành động gửi và nhận phải thay thế, luôn luôn bắt đầu với hành động gửi. Do đó, có 3 biến trạng thái cho trạng thái điều khiển là: ClientSocket, ServerSocket và Phase.

Trạng thái dữ liệu: là nhiệt độ đƣợc lƣu trữ trong bộ đệm nhận dữ liệu của client

clientBuffer.

Giá trị mong đợi trả về đƣợc tính toán sẵn: giới hạn 2 nhiệt độ là 99.9 và 100.0. Viết mã: các mã đƣợc viết bằng C# theo cấu trúc MP (chi tiết trong phần phụ lục).

MP kịch bản M2: đƣợc biểu diễn bởi máy trạng thái hữu hạn, M2 đƣợc lƣu trữ trong file scenario.txt:

Transitions( t(0,ServerSocket(),1), t(1,ServerBind(),2), t(2,ServerListen(),3), t(3,ClientSocket(),4), t(4,ClientConnect(),5), t(5,ServerAccept(),6), t(6,ClientClose(),7), t(7,ServerCloseConnection(),8), t(8,ServerClose(),9)))

Bƣớc thứ hai, sau khi đã có các MP đầu vào thì tiến hành phân tích chúng bằng công cụ mpv theo trình tự sau:

 Khởi động chƣơng trình cmd.exe.

 Gõ lệnh >build.bat để xây dựng các chƣơng trình thƣ viện.

 Gõ lệnh >mpv @mpv_contract.txt để hiển thị FSM đúng của MP. Khi đó đƣợc kết quả nhƣ hình 4.3:

Hình 4.3: FSM đúng của MP hợp đồng

Hình 4.3 hiển thị toàn bộ các trạng thái và đƣờng chạy (runs) của MP, trạng thái đƣợc đánh dấu đƣờng viền đậm là trạng thái kết thúc (trạng thái chấp nhận). Các trạng thái đƣợc tô màu vàng là các trạng thái không an toàn hoặc trạng thái chết.

 Gõ lệnh >mpv @mpv_scenario.txt để hiển thị FSM của MP kịch bản. Kết quả là FSM chỉ có duy nhất một đƣờng chạy đƣợc hiển thị nhƣ trong hình 4.4.

Hình 4.4: FSM của MP kịch bản

 Gõ lệnh >mpv @mpv_composition.txt để hiển thị FSM của MP kịch bản đƣợc biên soạn cùng với MP hợp đồng (FSM có sử dụng điều khiển kịch bản). Kết quả , ta nhận đƣợc thể hiện trong hình 4.5. FSM này đã đƣợc giới hạn tối ƣu về số lƣợng đƣờng chạy so với FSM của MP hợp đồng.

Bƣớc thứ ba, tạo các bộ kiểm thử (test suite) bởi công cụ otg:

 Gõ lệnh >otg @otg_contract.txt để tạo một bộ kiểm thử cho trƣờng hợp sử dụng MP hợp đồng. Tên tệp tin test suite là ContractTest.txt đƣợc lƣu trữ tự động trong cùng thƣ mục của MP. Bộ ca kiểm thử này gồm có 6 ca kiểm thử có nội dung nhƣ sau:

TestSuite( TestCase( ServerSocket(), ServerBind(), ClientSocket(), ServerListen(), ClientConnect(), ServerAccept(), ServerSend(double("99,9")), ServerCloseConnection(), ServerClose(), ClientReceive_Start(), ClientReceive_Finish(double("99,9")), ClientClose() ), TestCase( ClientSocket(), ServerSocket(), ServerBind(), ServerListen(), ClientConnect(), ServerAccept(), ClientSend(), ServerReceive(), ServerSend(double("99,9")), ClientReceive_Start(), ClientReceive_Finish(double("99,9")), ServerCloseConnection(), ServerClose(), ClientClose() ), TestCase( ClientSocket(), ServerSocket(), ServerBind(), ServerListen(), ClientConnect(), ServerAccept(), ServerSend(double("100")), ServerCloseConnection(), ClientReceive_Start(), ClientReceive_Finish(double("100")), ClientClose(), ServerClose() ), TestCase(

ServerSocket(), ServerBind(), ServerListen(), ClientSocket(), ClientConnect(), ServerAccept(), ClientClose(), ServerCloseConnection(), ServerClose() ), TestCase( ServerSocket(), ClientSocket(), ServerBind(), ServerListen(), ClientConnect(), ServerAccept(), ServerSend(double("100")), ClientReceive_Start(), ClientReceive_Finish(double("100")), ServerSend(double("100")), ServerCloseConnection(), ServerClose(), ClientReceive_Start(), ClientReceive_Finish(double("100")), ClientClose() ), TestCase( ClientSocket(), ServerSocket(), ServerBind(), ServerListen(), ClientConnect(), ServerAccept(), ServerSend(double("99,9")), ServerCloseConnection(), ClientReceive_Start(), ClientReceive_Finish(double("99,9")), ClientClose(), ServerClose() ) )

 Sau khi tạo bộ ca kiểm thử thì dùng lệnh >mpv @mpv_contract_test.txt để xem kết quả của bộ ca kiểm thử dƣới dạng FSM nhƣ trong hình 4.6.

 Gõ lệnh >otg @otg_scenario.txt để tạo ra một bộ ca kiểm thử đƣợc sinh ra từ MP hợp đồng đƣợc biên soạn với MP kịch bản (tên bộ kiểm thử là ScenarioTest.txt). Bộ kiểm thử này gồm có một ca kiểm thử duy nhất có nội dung nhƣ sau:

TestSuite( TestCase(

ServerBind(), ServerListen(), ClientSocket(), ClientConnect(), ServerAccept(), ServerSend(double("100")), ClientReceive_Start(), ClientReceive_Finish(double("100")), ServerSend(double("99,9")), ClientReceive_Start(), ClientReceive_Finish(double("99,9")), ClientSend(), ServerReceive(), ClientClose(), ServerCloseConnection(), ServerClose() ) )

 Sau đó sử dụng lệnh >mpv @mpv_scenario_test.txt để xem kết quả của bộ kiểm thử dƣới dạng FSM nhƣ trong hình 4.7.

Hình 4.7: FSM của một bộ kiểm thử đƣợc tạo khi MP hợp đồng biên soạn với MP kịch bản

Bƣớc cuối cùng là dùng công cụ ct để kiểm thử:

 Để chạy đƣợc kiểm thử, đầu tiên phải viết một bản khai thác kiểm thử (stepper) để kết nối implementation tới ct (stepper đƣợc trình bày trong phần phụ lục).  Gõ lệnh >build để xây dựng các thƣ viện của chƣơng trình

 Gõ lệnh >ct @ct_contract.txt để thực hiện kiểm thử ngoại tuyến từ MP hợp đồng (không sử dụng điều khiển kịch bản). Kết quả kiểm thử đƣợc thể hiện trong hình 4.8. Kiểm thử này báo thành công và không phát hiện ra lỗi hay khuyết tật.

 Gõ lệnh >ct @ct_scenario.txt để thực hiện kiểm thử ngoại tuyến đƣợc tạo ra từ MP hợp đồng đƣợc biên soạn với MP kịch bản. Kết quả của kiểm thử này báo lỗi đƣợc thể hiện nhƣ trong hình 4.9.

Hình 4.8: Kết quả kiểm thử ngoại tuyến với trƣờng hợp sử dụng MP hợp đồng

Hình 4.9: Kết quả kiểm thử ngoại tuyến với trƣờng hợp sử dụng điều khiển kịch bản (MP hợp đồng đƣợc biên soạn với MP kịch bản)

Nhƣ vậy là kiểm thử ngoại tuyến chƣơng trình client/server đã phát hiện ra lỗi (hình 4.9) khi một bộ kiểm thử có sử dụng điều khiển kịch bản. Thông điệp chỉ ra rằng kiểm thử này lỗi bởi vì giá trị trả về thực tế trong hành động cuối cùng là 99, không giống nhƣ giá trị trả về mong đợi 99.9 đã đƣợc tính bởi MP và đƣợc lƣu trữ trong ca kiểm thử.

Phân tích lỗi: Sau một vài điều tra tôi phát hiện ra khuyết tật là do các đoạn mã không chính xác (không đúng) gây ra các thất bại. Trong mã lệnh (code) của lớp Client đƣợc xây dựng có bộ đệm nhận của client chỉ đƣợc gán với 4 bytes long. Trong khi đó, tôi lại dự định là 40 chứ không phải 4. Đây là một lỗi đánh máy mà không bị bắt (caught) bởi trình biên dịch, bởi sự kiểm tra hoặc kiểm thử đơn vị. Khi server gửi nhiều hơn 4 ký tự, ví dụ nhƣ 100.0 thì client chỉ đọc đƣợc 4 ký tự đầu tiên là 100. Và sau đó các ký tự còn lại trong bộ đệm sẽ đƣợc nhận vào lần tiếp theo khi Client gọi phƣơng thức Receive. Bằng cách này, một mẫu nhiệt độ đơn giản có thể gây cho Client trở nên không đồng bộ với Server, kết quả là việc đọc không đúng sẽ xảy ra với một hoặc nhiều mẫu nhiệt độ tiếp theo.

Từ các kết quả kiểm thử trên tôi có thể so sánh kết quả và đánh giá kiểm thử ngoại tuyến trong hai trƣờng hợp kiểm thử ngoại tuyến không dùng điều khiển kịch bản (tức là chỉ sử dụng MP hợp đồng để sinh các test case tự động) và kiểm thử ngoại tuyến có sử dụng điều khiển kịch bản (kết hợp MP hợp đồng và MP kịch bản) nhƣ sau: trƣờng hợp không dùng điều khiển kịch bản thì có bộ test suite với nhiều test case nên việc kiểm thử không đƣợc kỹ lƣỡng và triệt để, do đó sẽ ít phát hiện ra lỗi hơn, cụ thể trong bài toán này là kiểm thử thành công không phát hiện đƣợc lỗi hay khuyết tật. Còn với trƣờng hợp có sử dụng điều khiển kịch bản thì bộ test suite có số lƣợng test case tối ƣu hơn (ở đây cụ thể là 1 test case) do đó việc kiểm thử sẽ đƣợc kỹ lƣỡng và triệt để hơn, sẽ phát hiện ra lỗi và khuyết tật tốt hơn.

4.2.2.2. Kiểm thử on-the-fly

Kiểm thử on-the-fly không cần phải tạo một bộ kiểm thử trƣớc mà chỉ cần implementation hoặc MP hoặc stepper. Kiểm thử on-the-fly là kiểm thử ngẫu nhiên.

Bƣớc 1: Tạo file ct_contract_random.txt với nội dung sau: /r:Stepper.dll

/iut:ClientServerImpl.Stepper.Create /r:...\Model\ClientServer.dll

/mp:ClientServer /runs:1

Bƣớc 2: Trên dòng lệnh cmd gõ lệnh >ct @ct_contract_random.txt để thực hiện kiểm thử ngẫu nhiên trong trƣờng hợp sử dụng MP hợp đồng. Kết quả kiểm thử này thông báo là gặp thất bại nhƣ trong hình 4.10.

Hình 4.10: Kết quả kiểm thử ngẫu nhiên khi sử dụng MP hợp đồng

Kiểm thử này bị gián đoạn dẫn đến trạng thái chết (mặc dù chọn ngẫu nhiên bất kỳ đƣờng chạy nào). Để kiểm thử đạt kết quả tốt, tệp tin ct đƣợc tạo có sử dụng điều khiển kịch bản ct_scenario_random.txt với nội dung sau:

/r:Stepper.dll /iut:ClientServerImpl.Stepper.Create /r:..\Model\ClientServer.dll /mp:ClientServer /fsm:..\Model\Scenario.txt /runs:1

Tiếp theo, trên chƣơng trình cmd gõ lệnh >ct @ct_scenario_random.txt để thực hiện kiểm thử ngẫu nhiên với trƣờng hợp sử dụng điều khiển kịch bản. Kết quả kiểm thử đƣợc chỉ ra nhƣ trong hình 4.11.

Kiểm thử này thành công bởi vì server đã không gửi 100 cho đến thông điệp cuối cùng. Sau đó, một vài kiểm thử ngẫu nhiên hơn sẽ chạy, ct thực hiện một đƣờng chạy thất bại, làm lộ khuyết tật nhƣ kết quả của đƣờng chạy đƣợc hiển thị trong hình 4.12.

Hình 4.12: Kết quả kiểm thử ngẫu nhiên khi sử dụng điều khiển kịch bản (2)

Tƣơng tự nhƣ phƣơng pháp kiểm thử ngoại tuyến, với trƣờng hợp kiểm thử có sử dụng điều khiển kịch bản của phƣơng pháp trực tuyến (on-the-fly) cũng đạt kết quả kiểm thử tốt hơn so với trƣờng hợp không sử dụng điều khiển kịch bản.

CHƢƠNG 5. KẾT LUẬN VÀ HƢỚNG PHÁT TRIỂN 5.1. Kết luận

Sau một thời gian nghiên cứu và thực hiện luận văn “Nghiên cứu ứng dụng “NModel” trong việc phát triển hệ thống nhúng thời gian thực”, luận văn của tôi đã đạt đƣợc những kết quả chính cũng nhƣ hƣớng phát triển của luận văn trong thời gian tới nhƣ sau:

Các kết quả chính đạt đƣợc và đóng góp trong luận văn.

- Tìm hiểu và nghiên cứu tài liệu về lý thuyết hệ thống nhúng, lý thuyết về phân tích và kiểm thử dựa trên mô hình: khái niệm chƣơng trình mô hình, khái niệm phân tích dựa trên mô hình, khái niệm kiểm thử dựa trên mô hình, khái niệm máy trạng thái hữu hạn.

- Cài đặt thành công NModel và .NET framework 3.5.

- Hiểu đƣợc quá trình phân tích và kiểm thử: Viết chƣơng trình mô hình, thực hiện thăm dò và phân tích MP hữu hạn, sinh bộ kiểm thử bằng công cụ otg, tiến hành kiểm thử ngoại tuyến bằng công cụ ct.

- Xây dựng đƣợc các chƣơng trình mô hình làm đầu vào cho công cụ từ bài toán thiết bị điều khiển từ xa – hệ thống Client/Server.

- Xây dựng các tệp tin có định dạng .txt (trong phần phụ lục) để điều khiển công cụ trong việc thực hiện phân tích và kiểm thử với NModel.

- Áp dụng quá trình phân tích và kiểm thử ngoại tuyến để kiểm thử thành công demo client/server với NModel.

5.2. Hƣớng phát triển

Trong luận văn này, tôi đã tìm hiểu và thực hiện đƣợc phân tích và kiểm thử dựa trên mô hình đối với hệ thống đóng có các trạng thái đơn giản. Demo với chƣơng trình nhỏ nhƣng đầy đủ. Tuy nhiên, do gặp khó khăn về mặt thời gian nên luận văn vẫn còn một số hạn chế là bài toán chƣa có điều kiện để cài đặt với hệ thống thực, và bài toán có khả năng chạy trên hệ thống thực nhƣng chƣa đáp ứng đƣợc về mặt thời gian thực. Do đó, trong tƣơng lai, tôi có hƣớng phát triển là: tôi sẽ tiếp tục tìm hiều và nghiên cứu về kiểm thử dựa trên mô hình với NModel trong hệ thống phản ứng có các trạng thái phức tạp, đáp ứng đƣợc về mặt thời gian thực.

TÀI LIỆU THAM KHẢO Tiếng Việt

1. TS. Lƣu Hồng Việt, “Tài liệu tóm tắt bài giảng Hệ thống điều khiển nhúng”, Đại học Bách Khoa Hà Nội.

Tiếng Anh

2. Colin Campbell, Margus Veanes, and Jonathan Jacky (2007, 2008), “NModel Reference”.

3. J. A. Cook J. S. Freudenberg (2008), “Embedded Software Architecture”, EECS 461.

4. Jonathan Jacky, Margus Veanes, Colin Campbell, Wolfram Schulte Cambridge University Press (2008, available December 2007), “Model-based Software Testing and Analysis with C#”, Cambridge University.

5. Juhan Ernits, Margus Veanes, and Johannes Helander (June 2008), “Model-Based Testing of Robots with NModel”.

6. Juhan Ernits, Rivo Roo, Jonathan Jacky, Margus Veanes (2009), “Model-Based Testing of Web Applications Using NModel”.

7. M. Veanes, C. Campbell, W. Grieskamp, L. Nachmanson, W. Schulte, and N. Tillmann (2005), Model-based testing of object-oriented reactive systems with Spec Explorer, Tech. Rep. MSR-TR-2005-59, Microsoft Research. Preliminary version of a book chapter in the forthcoming text book Formal Methods and Testing.

8. M. Broy, B. Jonsson, J.-P. Katoen, M. Leucker, and A. Pretschner (The volume is the outcome of a research seminar that was held in Schloss Dagstuhl in January 2004), editors, Model-Based Testing of Reactive Systems.

Website 9. http://nmodel.codeplex.com/ 10. http://blogs.msdn.com/b/specexplorer/archive/2009/10/27/what-is-model- based-testing.aspx 11. http://nmodelrs.berlios.de/ 12. http://www.kiemthuphanmem.com/blogs/3/24/model-based-testing-l-g-mbt) 13. http://voer.edu.vn/c/he-dieu-hanh-cho-cac-he-thong-nhung-hdh-thoi-gian- thuc/9f009757/07006533#.UzP9xc51mKE 14. http://www.testingvn.com/

PHỤ LỤC

HỆ THỐNG CLIENT/SERVER

Chƣơng trình mô hình contract client/server có tên là ClientServer: using NModel;

using NModel.Attributes; using NModel.Execution; namespace ClientServer {

public enum Socket { None, Created, Bound, Listening, Connecting, Connected, Disconnected, Closed }

public enum Phase { Send, ServerReceive, ClientReceive } public static class ClientServer

{

const double EmptyBuffer = double.MaxValue;

const double Temp2 = 99.9; // Temperature, 2 digits const double Temp3 = 100.0; // Temperature, 3 digits

// Biến trạng thái điều khiển

public static Socket serverSocket = Socket.None; public static Socket clientSocket = Socket.None; public static Phase phase = Phase.Send;

// Trạng thái dữ liệu

public static double clientBuffer = EmptyBuffer;

// Điều kiện trạng thái chấp nhận cho việc kiểm thử [AcceptingStateCondition]

static bool BothClosed() {

return (serverSocket == Socket.Closed && clientSocket == Socket.Closed); }

// Các điều kiện và hành động cho phép của Server public static bool ServerSocketEnabled()

{

return (serverSocket == Socket.None); }

[Action]

public static void ServerSocket() {

serverSocket = Socket.Created; }

public static bool ServerBindEnabled() {

return (serverSocket == Socket.Created); }

[Action]

public static void ServerBind() {

serverSocket = Socket.Bound; }

public static bool ServerListenEnabled() {

return (serverSocket == Socket.Bound); }

[Action]

public static void ServerListen() {

serverSocket = Socket.Listening; }

public static bool ServerAcceptEnabled() {

return (serverSocket == Socket.Listening && clientSocket ==

}

[Action]

public static void ServerAccept() {

serverSocket = Socket.Connected; clientSocket = Socket.Connected; }

public static bool ServerReceiveEnabled() {

return (serverSocket == Socket.Connected && phase == Phase.ServerReceive); }

// Các hành động Send ở trong MP này không cần tham số [Action]

public static void ServerReceive() {

phase = Phase.Send; }

public static bool ServerSendEnabled() {

return (serverSocket == Socket.Connected

&& phase == Phase.Send && clientSocket == Socket.Connected); }

// Dùng tham số ở đây, Server có thể gửi các nhiệt độ khác nhau [Action]

public static void ServerSend([Domain("Temperatures")] double datum) {

clientBuffer = datum;

phase = Phase.ClientReceive; }

// Tên miền cho tham số ServerSend là t static Set<double> Temperatures() {

return new Set<double>(Temp2, Temp3); }

public static bool ServerCloseConnectionEnabled() {

return (serverSocket == Socket.Connected); }

[Action]

public static void ServerCloseConnection() {

serverSocket = Socket.Disconnected; }

// Ngăn chặn Client bị treo

public static bool ServerCloseEnabled() {

return (serverSocket != Socket.None

// && serverSocket != Socket.Listening

&& serverSocket != Socket.Connected && serverSocket != Socket.Closed); }

[Action]

public static void ServerClose() {

serverSocket = Socket.Closed; }

// Các điều kiện và hành động được phép của Client public static bool ClientSocketEnabled()

{

return (clientSocket == Socket.None); }

[Action]

public static void ClientSocket() {

clientSocket = Socket.Created; }

public static bool ClientConnectEnabled() {

return (clientSocket == Socket.Created && serverSocket ==

Socket.Listening); }

[Action]

public static void ClientConnect() {

clientSocket = Socket.Connecting; }

public static bool ClientSendEnabled() {

return (clientSocket == Socket.Connected && phase == Phase.Send); }

// Hành động Send của client ko có tham số

Một phần của tài liệu Nghiên cứu ứng dụng “NModel” trong việc phát triển hệ thống nhúng thời gian thực (Trang 57)