Phương thức xác nhận phpunit được gọi với các đối số
Hành vi của diễn viên là mô phỏng các đối tượng khó thiết lập hoặc tốn thời gian để thiết lập để thử nghiệm. Ví dụ cổ điển là một kết nối cơ sở dữ liệu. Việc thiết lập cơ sở dữ liệu thử nghiệm khi bắt đầu mỗi lần thử nghiệm sẽ làm chậm quá trình thử nghiệm khi thu thập dữ liệu và sẽ yêu cầu cài đặt công cụ cơ sở dữ liệu và dữ liệu thử nghiệm trên máy thử nghiệm. Nếu chúng tôi có thể mô phỏng kết nối và trả về dữ liệu theo lựa chọn của mình, chúng tôi không chỉ giành chiến thắng về tính thực dụng của thử nghiệm mà còn có thể cung cấp dữ liệu giả cho mã của chúng tôi để xem nó phản hồi như thế nào. Chúng tôi có thể mô phỏng cơ sở dữ liệu đang ngừng hoạt động hoặc các trạng thái cực đoan khác mà không cần phải tạo cơ sở dữ liệu bị hỏng thực sự. Nói cách khác, chúng tôi có quyền kiểm soát tốt hơn đối với môi trường thử nghiệm Show Nếu các đối tượng giả chỉ hoạt động như các diễn viên, chúng sẽ được gọi đơn giản là sơ khai máy chủ. Đây ban đầu là một mẫu được đặt tên bởi Robert Binder (Thử nghiệm hệ thống hướng đối tượng. mô hình, mẫu và công cụ, Addison-Wesley) vào năm 1999 Sơ khai máy chủ là mô phỏng của một đối tượng hoặc thành phần. Nó sẽ thay thế chính xác một thành phần trong hệ thống cho mục đích thử nghiệm hoặc tạo mẫu, nhưng vẫn nhẹ. Điều này cho phép các bài kiểm tra chạy nhanh hơn hoặc nếu lớp mô phỏng chưa được viết, vẫn chạy được Tuy nhiên, các đối tượng giả không chỉ đóng một phần (bằng cách cung cấp các giá trị trả về đã chọn theo yêu cầu) mà chúng còn nhạy cảm với các thông báo được gửi tới chúng (thông qua kỳ vọng). Bằng cách thiết lập các tham số dự kiến cho một lệnh gọi phương thức, chúng hoạt động như một người bảo vệ rằng các lệnh gọi chúng được thực hiện chính xác. Nếu kỳ vọng không được đáp ứng, chúng tôi sẽ tiết kiệm công sức viết xác nhận kiểm tra không thành công bằng cách thay mặt chúng tôi thực hiện nghĩa vụ đó Trong trường hợp kết nối cơ sở dữ liệu tưởng tượng, họ có thể kiểm tra xem truy vấn, chẳng hạn như SQL, được tạo chính xác bởi đối tượng đang sử dụng kết nối. Thiết lập chúng với những kỳ vọng khá chặt chẽ và bạn sẽ hầu như không cần đến các xác nhận thủ công Tạo các đối tượng giảCũng giống như cách chúng ta tạo sơ khai máy chủ, tất cả những gì chúng ta cần là một lớp hiện có, giả sử một kết nối cơ sở dữ liệu giống như thế này class DatabaseConnection { function DatabaseConnection() { } function query() { } function selectQuery() { } }Lớp chưa cần triển khai. Để tạo một phiên bản giả của lớp, chúng ta cần bao gồm thư viện đối tượng giả và chạy trình tạo. require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');Điều này tạo ra một lớp nhân bản có tên là MockDatabaseConnection. Bây giờ chúng ta có thể tạo các thể hiện của lớp mới trong trường hợp thử nghiệm của mình. require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection'); class MyTestCase extends UnitTestCase { function testSomething() { $connection = &new MockDatabaseConnection(); } }Không giống như sơ khai được tạo, hàm tạo mô phỏng cần tham chiếu đến trường hợp thử nghiệm để nó có thể gửi các lượt vượt qua và lỗi trong khi kiểm tra các kỳ vọng của nó. Điều này có nghĩa là các đối tượng giả chỉ có thể được sử dụng trong các trường hợp thử nghiệm. Mặc dù vậy, sức mạnh bổ sung của chúng có nghĩa là sơ khai hầu như không được sử dụng nếu có sẵn giả Giả làm diễn viênPhiên bản giả của một lớp có tất cả các phương thức của bản gốc, do đó các thao tác như $connection->query() vẫn hợp lệ. Giá trị trả về sẽ là null, nhưng chúng ta có thể thay đổi giá trị đó bằng $connection->setReturnValue('query', 37)Bây giờ mỗi khi chúng ta gọi $connection->query() chúng ta sẽ nhận được kết quả là 37. Chúng ta có thể đặt giá trị trả về thành bất kỳ thứ gì, chẳng hạn như hàm băm của kết quả cơ sở dữ liệu tưởng tượng hoặc danh sách các đối tượng liên tục. Các tham số không liên quan ở đây, chúng tôi luôn nhận lại các giá trị giống nhau mỗi khi chúng được thiết lập theo cách này. Điều đó nghe có vẻ không giống như một bản sao thuyết phục của kết nối cơ sở dữ liệu, nhưng đối với nửa tá dòng của phương pháp kiểm tra, đó thường là tất cả những gì bạn cần Chúng ta cũng có thể thêm các phương thức bổ sung vào mô phỏng khi tạo nó và chọn tên lớp của riêng mình Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));Ở đây mô hình sẽ hoạt động như thể setOptions() đã tồn tại trong lớp ban đầu. Điều này rất hữu ích nếu một lớp đã sử dụng cơ chế quá tải () của PHP để thêm các phương thức động. Bạn có thể tạo một mô phỏng đặc biệt để mô phỏng tình huống này Mọi thứ không phải lúc nào cũng đơn giản như vậy. Một vấn đề phổ biến là các trình vòng lặp, trong đó việc liên tục trả về cùng một giá trị có thể gây ra một vòng lặp vô tận trong đối tượng đang được kiểm tra. Đối với những điều này, chúng ta cần thiết lập các chuỗi giá trị. Giả sử chúng ta có một iterator đơn giản trông như thế này class Iterator { function Iterator() { } function next() { } }Đây là về iterator đơn giản nhất mà bạn có thể có. Giả sử rằng trình vòng lặp này chỉ trả về văn bản cho đến khi nó kết thúc, khi nó trả về false, chúng ta có thể mô phỏng nó bằng. Mock::generate('Iterator'); class IteratorTest extends UnitTestCase() { function testASequence() { $iterator = &new MockIterator(); $iterator->setReturnValue('next', false); $iterator->setReturnValueAt(0, 'next', 'First string'); $iterator->setReturnValueAt(1, 'next', 'Second string'); ... } }Khi next() được gọi trên trình lặp mô phỏng, trước tiên nó sẽ trả về "Chuỗi đầu tiên", ở lần gọi thứ hai "Chuỗi thứ hai" sẽ được trả về và trên bất kỳ lệnh gọi nào khác, false sẽ được trả về. Các giá trị trả về theo trình tự được ưu tiên hơn giá trị trả về không đổi. Hằng số là một loại mặc định nếu bạn thích Một tình huống phức tạp khác là thao tác get() bị quá tải. Một ví dụ về điều này là một người giữ thông tin với các cặp tên/giá trị. Giả sử chúng ta có một lớp cấu hình như class Configuration { function Configuration() { } function getValue($key) { } }Đây là một tình huống cổ điển khi sử dụng các đối tượng giả vì cấu hình thực tế sẽ thay đổi từ máy này sang máy khác, hầu như không giúp tăng độ tin cậy của các thử nghiệm nếu chúng tôi sử dụng trực tiếp. Tuy nhiên, vấn đề là tất cả dữ liệu đều đến từ phương thức getValue() và chúng tôi muốn các kết quả khác nhau cho các khóa khác nhau. May mắn thay, các mô phỏng có một hệ thống lọc. $config = &new MockConfiguration(); $config->setReturnValue('getValue', 'primary', array('db_host')); $config->setReturnValue('getValue', 'admin', array('db_user')); $config->setReturnValue('getValue', 'secret', array('db_password'));Tham số bổ sung là danh sách các đối số để cố khớp. Trong trường hợp này, chúng tôi đang cố gắng chỉ khớp một đối số là khóa tra cứu. Bây giờ khi đối tượng giả có phương thức getValue() được gọi như thế này. $config->getValue('db_user'). nó sẽ trả về "admin". Nó tìm thấy điều này bằng cách cố gắng khớp các đối số đang gọi với danh sách trả về của nó lần lượt cho đến khi tìm thấy một kết quả khớp hoàn chỉnh Bạn có thể đặt đối số đối số mặc định như vậy require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');0Điều này không giống với việc đặt giá trị trả về mà không có bất kỳ yêu cầu đối số nào như thế này. require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');1Trong trường hợp đầu tiên, nó sẽ chấp nhận bất kỳ đối số nào, nhưng bắt buộc phải có chính xác một đối số. Trong trường hợp thứ hai, bất kỳ số lượng đối số nào cũng được và nó đóng vai trò là một đối số sau tất cả các đối số khác. Lưu ý rằng nếu chúng ta thêm các tùy chọn tham số đơn khác sau ký tự đại diện trong trường hợp đầu tiên, chúng sẽ bị bỏ qua vì ký tự đại diện sẽ khớp trước. Với các danh sách tham số phức tạp, thứ tự có thể quan trọng nếu không các kết quả phù hợp mong muốn có thể bị che dấu bởi các ký tự đại diện trước đó. Khai báo các kết quả khớp cụ thể nhất trước nếu bạn không chắc chắn Đôi khi bạn muốn một đối tượng cụ thể được mô phỏng loại bỏ hơn là một bản sao. Ngữ nghĩa sao chép PHP4 buộc chúng tôi phải sử dụng một phương pháp khác cho việc này. Bạn có thể đang mô phỏng một container chẳng hạn require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');2Trong trường hợp này, bạn có thể đặt tham chiếu vào danh sách trả về của mô hình. require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');3Với sự sắp xếp này, bạn biết rằng mỗi lần $vector->get(12) được gọi, nó sẽ trả về cùng một $thing mỗi lần. Điều này cũng tương thích với PHP5 Ba yếu tố này, thời gian, tham số và liệu có sao chép hay không, có thể được kết hợp trực giao. Ví dụ require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');4Điều này sẽ chỉ trả về $stuff trong lần gọi thứ ba và chỉ khi hai tham số được đặt, tham số thứ hai phải là số nguyên 1. Điều đó sẽ bao gồm hầu hết các tình huống tạo mẫu đơn giản Trường hợp phức tạp cuối cùng là một đối tượng tạo ra một đối tượng khác, được gọi là mẫu xuất xưởng. Giả sử rằng trên một truy vấn thành công tới cơ sở dữ liệu tưởng tượng của chúng ta, một tập kết quả được trả về dưới dạng một trình vòng lặp với mỗi lệnh gọi next() đưa ra một hàng cho đến khi sai. Điều này nghe giống như một cơn ác mộng mô phỏng, nhưng trên thực tế, tất cả đều có thể bị chế giễu bằng cách sử dụng các cơ chế ở trên Đây là cách require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');5Bây giờ chỉ khi kết nối $ của chúng tôi được gọi với truy vấn chính xác () thì kết quả $ sẽ được trả về mà chính nó đã hết sau lần gọi thứ ba tới next(). Đây phải là thông tin đủ cho lớp UserFinder của chúng tôi, lớp thực sự đang được thử nghiệm ở đây, để đưa ra hàng hóa. Một bài kiểm tra rất chính xác và không phải là cơ sở dữ liệu thực trong tầm nhìn Chế giễu như những nhà phê bìnhMặc dù cách tiếp cận sơ khai máy chủ bảo vệ các bài kiểm tra của bạn khỏi sự gián đoạn trong thế giới thực, nhưng nó chỉ mang lại một nửa lợi ích. Bạn có thể yêu cầu lớp đang kiểm tra nhận các tin nhắn được yêu cầu, nhưng lớp mới của bạn có gửi đúng tin nhắn không? Ví dụ, giả sử chúng ta có một lớp SessionPool mà chúng ta muốn thêm ghi nhật ký vào. Thay vì phát triển lớp ban đầu thành một thứ gì đó phức tạp hơn, chúng tôi muốn thêm hành vi này bằng một trình trang trí (GOF). Mã SessionPool hiện trông như thế này require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');6Trong khi mã đăng nhập của chúng tôi trông như thế này. require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');7Trong số tất cả những thứ này, lớp duy nhất chúng tôi muốn kiểm tra ở đây là LoggingSessionPool. Cụ thể, chúng tôi muốn kiểm tra xem phương thức findSession() có được gọi với ID phiên chính xác trong cookie hay không và phương thức này đã gửi thông báo "Đang bắt đầu phiên $cookie" tới bộ ghi nhật ký Mặc dù thực tế là chúng tôi chỉ kiểm tra một vài dòng mã sản xuất, đây là những gì chúng tôi sẽ phải làm trong một trường hợp thử nghiệm thông thường
Thay vào đó, đây là phương pháp kiểm tra hoàn chỉnh bằng cách sử dụng ma thuật đối tượng giả require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');8Chúng tôi bắt đầu bằng cách tạo một phiên giả. Chúng tôi không cần phải quá cầu kỳ về điều này vì việc kiểm tra phiên nào chúng tôi muốn được thực hiện ở nơi khác. Chúng tôi chỉ cần kiểm tra xem đó có phải là phiên bản đến từ nhóm phiên không findSession() là một phương thức xuất xưởng mô phỏng được mô tả. Điểm khởi hành đi kèm với lời gọi đầu tiên kỳ vọng(). Dòng này nói rằng bất cứ khi nào findSession() được gọi trên mô hình giả, nó sẽ kiểm tra các đối số đến. Nếu nó nhận được một đối số duy nhất của một chuỗi "abc" thì một bài kiểm tra sẽ được gửi đến bộ kiểm tra đơn vị, nếu không thì một lỗi sẽ được tạo. Đây là phần mà chúng tôi đã kiểm tra xem phiên phù hợp đã được yêu cầu chưa. Danh sách đối số tuân theo định dạng giống như danh sách để đặt giá trị trả về. Bạn có thể có các ký tự đại diện và trình tự và thứ tự đánh giá là như nhau Chúng tôi sử dụng cùng một mẫu để thiết lập bộ ghi giả. Chúng tôi nói với nó rằng nó nên có message() được gọi một lần duy nhất với đối số "Bắt đầu phiên abc". Bằng cách kiểm tra các đối số gọi, thay vì đầu ra của bộ ghi, chúng tôi cách ly kiểm tra khỏi bất kỳ thay đổi hiển thị nào trong bộ ghi Chúng tôi bắt đầu chạy thử nghiệm khi chúng tôi tạo LoggingSessionPool mới và cung cấp cho nó các đối tượng giả định sẵn của chúng tôi. Mọi thứ bây giờ nằm trong tầm kiểm soát của chúng tôi Đây vẫn là một đoạn mã kiểm tra khá ít, nhưng mã rất nghiêm ngặt. Nếu nó vẫn có vẻ khá khó khăn thì sẽ ít hơn rất nhiều so với việc chúng tôi thử điều này mà không có mô phỏng và thử nghiệm cụ thể này, các tương tác thay vì đầu ra, luôn cần nhiều công việc hơn để thiết lập. Thường xuyên hơn, bạn sẽ kiểm tra các tình huống phức tạp hơn mà không cần mức độ hoặc độ chính xác này. Ngoài ra, một số trong số này có thể được tái cấu trúc thành phương thức setUp() trong trường hợp thử nghiệm Đây là danh sách đầy đủ các kỳ vọng bạn có thể đặt trên một đối tượng giả trong SimpleTest Ngoài ra, nếu bạn chỉ có một cuộc gọi trong thử nghiệm của mình, hãy đảm bảo rằng bạn đang sử dụng kỳ vọng Giống như các xác nhận trong các trường hợp thử nghiệm, tất cả các kỳ vọng có thể ghi đè thông báo làm tham số bổ sung. Ngoài ra, thông báo lỗi ban đầu có thể được nhúng trong đầu ra dưới dạng "%s" cách tiếp cận khácCó ba cách tiếp cận để tạo mô hình giả bao gồm cả cách mà SimpleTest sử dụng. Mã hóa chúng bằng tay bằng cách sử dụng một lớp cơ sở, tạo chúng thành một tệp và tự động tạo chúng một cách nhanh chóng Các đối tượng giả được tạo bằng SimpleTest là động. Chúng được tạo trong thời gian chạy trong bộ nhớ, sử dụng eval(), thay vì ghi ra tệp. Điều này làm cho các mô hình giả dễ dàng tạo ra, một lớp lót, đặc biệt là so với việc tạo thủ công chúng trong hệ thống phân cấp lớp song song. Vấn đề là hành vi thường được thiết lập trong các bài kiểm tra. Nếu các đối tượng ban đầu thay đổi các phiên bản mô phỏng mà các bài kiểm tra dựa vào có thể không đồng bộ. Điều này cũng có thể xảy ra với cách tiếp cận phân cấp song song, nhưng được phát hiện nhanh hơn nhiều Tất nhiên, giải pháp là thêm một số thử nghiệm tích hợp thực tế. Bạn không cần quá nhiều và sự tiện lợi thu được từ các bản mô phỏng vượt xa số lượng thử nghiệm bổ sung nhỏ. Bạn không thể tin tưởng mã chỉ được thử nghiệm với mô hình giả Nếu bạn vẫn quyết tâm xây dựng các thư viện mô phỏng tĩnh vì bạn muốn mô phỏng hành vi rất cụ thể, bạn có thể đạt được hiệu quả tương tự bằng cách sử dụng trình tạo lớp SimpleTest. Trong tệp thư viện của bạn, giả sử mocks/connection. php để kết nối cơ sở dữ liệu, tạo mô hình giả và kế thừa để ghi đè các phương thức đặc biệt hoặc thêm giá trị đặt trước require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection');9Cuộc gọi tạo yêu cầu trình tạo lớp tạo một lớp có tên là BasicMockConnection thay vì MockConnection thông thường. Sau đó, chúng tôi kế thừa từ điều này để có phiên bản MockConnection của chúng tôi. Bằng cách chặn theo cách này, chúng tôi có thể thêm hành vi, ở đây đặt giá trị mặc định của query() thành false. Bằng cách sử dụng tên mặc định, chúng tôi đảm bảo rằng trình tạo lớp giả sẽ không tạo lại một tên khác khi được gọi ở nơi khác trong các bài kiểm tra. Nó không bao giờ tạo một lớp nếu nó đã tồn tại. Miễn là tệp trên được đưa vào trước thì tất cả các thử nghiệm đã tạo MockConnection bây giờ sẽ sử dụng tệp của chúng tôi để thay thế. Nếu chúng ta không sắp xếp đúng thứ tự và thư viện giả tạo trước thì việc tạo lớp sẽ thất bại Sử dụng thủ thuật này nếu bạn thấy mình có nhiều hành vi giả định phổ biến hoặc bạn thường xuyên gặp sự cố tích hợp ở các giai đoạn thử nghiệm sau này Làm cách nào để thử một phương thức trong PHPUnit?PHPUnit cung cấp các phương thức được sử dụng để tự động tạo các đối tượng sẽ thay thế đối tượng ban đầu trong thử nghiệm của chúng tôi. Các phương thức createMock($type) và getMockBuilder($type) được sử dụng để tạo đối tượng giả . Phương thức createMock ngay lập tức trả về một đối tượng giả của loại đã chỉ định.
Khẳng định trong PHPUnit là gì?Hàm assertSame() PHPUnit
. Xác nhận này sẽ trả về true trong trường hợp nếu giá trị mong đợi giống với giá trị thực tế, ngược lại trả về false. used to assert whether the actually obtained value is the same as the expected value or not. This assertion will return true in the case if the expected value is the same as the actual value else returns false.
PHPUnit có phải là một khuôn khổ không?PHPUnit là khung thử nghiệm dành cho lập trình viên dành cho PHP . Nó là một ví dụ về kiến trúc xUnit cho các khung kiểm tra đơn vị. PHPUnit 9 là phiên bản ổn định hiện tại. PHPUnit 10 hiện đang được phát triển. |