Khi bạn đang làm việc trên một tính năng phụ thuộc vào thời gian ... Làm thế nào để bạn tổ chức thử nghiệm đơn vị? Khi đơn vị kiểm tra các kịch bản phụ thuộc vào cách chương trình của bạn diễn giải "ngay bây giờ", làm thế nào để bạn thiết lập chúng?
Chỉnh sửa thứ hai: Sau một vài ngày đọc kinh nghiệm của bạn
Tôi có thể thấy rằng các kỹ thuật để đối phó với tình huống này thường xoay quanh một trong ba nguyên tắc sau:
- Thêm (mã cứng) một phụ thuộc: thêm một lớp nhỏ qua hàm / đối tượng thời gian và luôn gọi hàm datetime của bạn thông qua lớp này. Bằng cách này, bạn có thể kiểm soát thời gian trong các trường hợp thử nghiệm.
- Sử dụng giả: mã của bạn giữ nguyên chính xác. Trong các thử nghiệm của bạn, bạn thay thế đối tượng thời gian bằng một đối tượng thời gian giả. Đôi khi, giải pháp liên quan đến việc sửa đổi đối tượng thời gian thực được cung cấp bởi ngôn ngữ lập trình của bạn.
- Sử dụng nội xạ phụ thuộc: Xây dựng mã của bạn để bất kỳ tham chiếu thời gian nào được truyền dưới dạng tham số. Sau đó, bạn có quyền kiểm soát các tham số trong các bài kiểm tra.
Các kỹ thuật (hoặc thư viện) dành riêng cho một ngôn ngữ rất được hoan nghênh và sẽ được nâng cao nếu một đoạn mã minh họa xuất hiện. Sau đó, thú vị nhất là làm thế nào các nguyên tắc tương tự có thể được áp dụng trên bất kỳ nền tảng nào. Và vâng ... Nếu tôi có thể áp dụng nó ngay lập tức trong PHP, tốt hơn là tốt hơn;)
Hãy bắt đầu với một ví dụ đơn giản: một ứng dụng đặt phòng cơ bản.
Giả sử chúng ta có API JSON và hai thông báo: thông báo yêu cầu và thông báo xác nhận. Một kịch bản tiêu chuẩn diễn ra như sau:
- Bạn đưa ra yêu cầu. Bạn nhận được phản hồi với mã thông báo. Tài nguyên cần thiết để thực hiện yêu cầu đó bị hệ thống chặn trong 5 phút.
- Bạn xác nhận một yêu cầu, được xác định bởi mã thông báo. Nếu mã thông báo được phát hành trong vòng 5 phút, nó sẽ được chấp nhận (tài nguyên vẫn có sẵn). Nếu hơn 5 phút trôi qua, bạn phải đưa ra yêu cầu mới (tài nguyên đã được giải phóng. Bạn cần kiểm tra lại tính khả dụng của nó một lần nữa).
Ở đây có kịch bản thử nghiệm tương ứng:
Tôi đưa ra yêu cầu. Tôi xác nhận (ngay lập tức) với mã thông báo tôi nhận được. Xác nhận của tôi được chấp nhận.
Tôi đưa ra yêu cầu. Tôi đợi 3 phút. Tôi xác nhận với mã thông báo tôi nhận được. Xác nhận của tôi được chấp nhận.
Tôi đưa ra yêu cầu. Tôi đợi 6 phút. Tôi xác nhận với mã thông báo tôi nhận được. Xác nhận của tôi bị từ chối.
Làm thế nào chúng ta có thể lập trình các bài kiểm tra đơn vị này? Kiến trúc nào chúng ta nên sử dụng để các chức năng này vẫn có thể kiểm tra được?
Chỉnh sửa Lưu ý: Khi chúng tôi thực hiện một yêu cầu, thời gian được lưu trữ trong cơ sở dữ liệu ở định dạng mất bất kỳ thông tin nào về mili giây.
EXTRA - nhưng có lẽ hơi dài dòng: Ở đây có chi tiết về những gì tôi phát hiện ra khi làm "bài tập về nhà" của mình:
Tôi đã xây dựng tính năng của mình với sự phụ thuộc vào chức năng thời gian của riêng tôi. Hàm VirtualDateTime của tôi có một phương thức tĩnh get_time () mà tôi gọi nơi tôi đã sử dụng để gọi DateTime () mới. Chức năng thời gian này cho phép tôi mô phỏng và kiểm soát thời gian là "bây giờ", để tôi có thể xây dựng các bài kiểm tra như: "Đặt ngay bây giờ đến ngày 21 tháng 1 năm 2014 16h15. Đưa ra yêu cầu. Di chuyển trước 3 phút. Xác nhận." Điều này hoạt động tốt, với chi phí của sự phụ thuộc và "mã không đẹp lắm".
Một giải pháp tích hợp hơn một chút sẽ là xây dựng hàm myDateTime của riêng tôi để mở rộng DateTime với các chức năng "thời gian ảo" bổ sung (quan trọng nhất là đặt ngay bây giờ thành những gì tôi muốn). Điều này làm cho mã của giải pháp đầu tiên thanh lịch hơn một chút (sử dụng myDateTime mới thay vì DateTime mới), nhưng kết thúc rất giống nhau: Tôi phải xây dựng tính năng của mình bằng lớp của riêng mình, do đó tạo ra sự phụ thuộc.
Tôi có mặc dù về việc hack chức năng DateTime, để làm cho nó hoạt động với sự phụ thuộc của tôi khi tôi cần. Có cách nào đơn giản và gọn gàng để thay thế một lớp bằng một lớp khác không? (Tôi nghĩ rằng tôi đã có câu trả lời cho điều đó: Xem không gian tên bên dưới).
Trong môi trường PHP, tôi đọc "Runkit" có thể cho phép tôi thực hiện việc này (hack chức năng DateTime) một cách linh hoạt. Điều tuyệt vời là tôi sẽ có thể kiểm tra tôi đang chạy trong môi trường thử nghiệm trước khi sửa đổi bất cứ điều gì về DateTime và để nó không bị ảnh hưởng trong sản xuất [1] . Điều này nghe có vẻ an toàn và sạch sẽ hơn bất kỳ hack DateTime thủ công nào.
Sự phụ thuộc của hàm đồng hồ trong mỗi lớp sử dụng thời gian [2] . Đây không phải là quá mức? Tôi thấy rằng trong một số môi trường, nó rất hữu ích [5] . Trong trường hợp này, tôi không thích nó lắm.
Loại bỏ sự phụ thuộc thời gian trong tất cả các chức năng [2] . Điều này luôn luôn khả thi? (Xem thêm ví dụ dưới đây)
Sử dụng không gian tên [2] [3] ? Điều này có vẻ khá tốt. Tôi có thể giả định DateTime bằng chức năng DateTime của riêng mình kéo dài \ DateTime ... Sử dụng DateTime :: setNow ("2014-01-21 16:15:00") và DateTime :: chờ đợi ("+ 3 phút"). Điều này bao gồm khá nhiều những gì tôi cần. Nếu chúng ta sử dụng hàm time () thì sao? Hoặc các chức năng thời gian khác? Tôi vẫn phải tránh sử dụng chúng trong mã gốc của tôi. Hoặc tôi sẽ cần đảm bảo bất kỳ hàm thời gian PHP nào tôi sử dụng trong mã của mình bị ghi đè trong các thử nghiệm của mình ... Có thư viện nào có sẵn để làm việc này không?
Tôi đã tìm kiếm một cách để thay đổi thời gian hệ thống chỉ cho một chủ đề. Dường như không có [4] . Đây là một điều đáng tiếc: một hàm PHP "đơn giản" thành "Đặt thời gian thành ngày 21 tháng 1 năm 2014 16h15 cho chủ đề này" sẽ là một tính năng tuyệt vời cho loại thử nghiệm này.
Thay đổi ngày và giờ hệ thống để kiểm tra, sử dụng exec (). Điều này có thể giải quyết nếu bạn không sợ làm hỏng những thứ khác trên máy chủ. Và bạn cần thiết lập lại thời gian hệ thống sau khi bạn chạy thử nghiệm. Nó có thể thực hiện các mẹo trong một số tình huống, nhưng cảm thấy khá "hacky".
Điều này có vẻ như là một vấn đề rất tiêu chuẩn với tôi. Tuy nhiên, tôi vẫn bỏ lỡ một cách đơn giản để đối phó với nó. Có lẽ tôi đã bỏ lỡ điều gì? Hãy chia sẻ kinh nghiệm của bạn!
LƯU Ý: Dưới đây là một số tình huống khác mà chúng tôi có thể có nhu cầu thử nghiệm tương tự.
Bất kỳ tính năng nào hoạt động với một số loại thời gian chờ (ví dụ: trò chơi cờ vua?)
xử lý hàng đợi kích hoạt các sự kiện tại một thời điểm nhất định (trong kịch bản trên, chúng ta có thể tiếp tục như vậy: một ngày trước khi đặt chỗ bắt đầu, tôi muốn gửi thư cho người dùng với tất cả các chi tiết. Kịch bản thử nghiệm ...)
Bạn muốn thiết lập một môi trường thử nghiệm với dữ liệu được thu thập trong quá khứ - bạn muốn thấy nó giống như bây giờ. [1]
1 /programming/3271735/simulation-different-server-datetimes-in-php
2 /programming/4221480/how-to-change-civerse-time-for-unit-testing-date-fifts-in-php
3 http://www.schmengler-se.de/en/2011/03/php-mocking-built-in-fifts-like-time-in-unit-tests/
DateTime now
vào mã thay vì đồng hồ sẽ đơn giản hơn .