Computer >> Máy Tính >  >> Lập trình >> Ruby

Kiểm tra các dịch vụ mạng trong Ruby dễ dàng hơn bạn nghĩ

Bạn đã bắt đầu một dự án mới và đã đến lúc mã của bạn phụ thuộc vào dịch vụ của bên thứ ba. Nó có thể là một cái gì đó giống như ElasticSearch, Resque, một nhà cung cấp thanh toán hoặc chỉ một API HTTP tùy ý. Bạn là một nhà phát triển giỏi, vì vậy bạn muốn mã này được kiểm tra tốt. Nhưng làm cách nào để bạn kiểm tra mã kích hoạt yêu cầu đối với một dịch vụ hoàn toàn nằm ngoài tầm kiểm soát của bạn?

Bạn có thể bỏ qua các bài kiểm tra, nhưng bạn sẽ sớm xếp chồng nhiều mã hơn trên nền tảng vững chắc. Mã chưa được kiểm tra có xu hướng thu hút nhiều mã phức tạp hơn và cuối cùng bạn sẽ cảm thấy như mã quá nguy hiểm để trở thành yếu tố vì bạn không có phạm vi kiểm tra mà bạn cần để cảm thấy an toàn. Bạn muốn xây dựng một nền tảng ổn định cho công việc tương lai của mình, nhưng hãy nghĩ rằng bạn đã kết thúc với một mớ hỗn độn không thể giải thích được.

Tránh tình huống này dễ dàng hơn rất nhiều so với tưởng tượng! Với một vài công cụ và một chút nỗ lực từ trước, bạn có thể tách các thử nghiệm của mình khỏi các dịch vụ mà mã của bạn phụ thuộc vào, viết mã đơn giản hơn và có đủ tự tin để cải thiện mã bạn đã viết – mà không cần giới thiệu lỗi. Thay vì trì hoãn vì bạn không biết cách tiếp cận để viết các thử nghiệm tiếp theo đó, bạn có thể xem xét sự tương tác giữa mã của bạn và thế giới bên ngoài và biết chính xác cách bắt đầu ngay giữa nó.

Mocha:cách tiếp cận nhanh chóng và hiệu quả

Mocha là cách dễ dàng nhất để chuyển đổi giữa mã của bạn và thế giới bên ngoài.

Ví dụ:giả sử bạn có Cart đối tượng kích hoạt tính phí thẻ tín dụng khi nó được thanh toán. Bạn muốn đảm bảo rằng xe đẩy có thông báo lỗi kèm theo nếu tính phí không thành công.

Có thể bạn sẽ không muốn các bài kiểm tra của mình thực sự thành công hệ thống lập hóa đơn mỗi khi chạy thử nghiệm. Ngay cả khi bạn đã làm vậy, có thể khó mà buộc dịch vụ đó trả lại lỗi. Đây là những gì nó sẽ trông như thế nào với Mocha:

def test_error_message_set_on_charge_failure
  cart = Cart.new(items)
  cart.stubs(:charge!).returns(false) # mocha in action
  cart.checkout!
  assert_equal "The credit card could not be charged", cart.credit_card_error
end

Mocha cũng có thể không thực hiện được các bài kiểm tra của bạn nếu các phương pháp không được gọi như cách bạn mong đợi:

def test_only_bill_once_per_cart
  cart = Cart.new(items)
  cart.expects(:charge!).once # Don't double-bill, no matter how many times we check out
  cart.checkout!
  cart.checkout!
end

Mocha rất đơn giản để sử dụng, nhưng có thể vô cùng tiện dụng. Bạn phải cẩn thận rằng bạn đang chế giễu chỉ hành vi mà bạn không muốn xảy ra - rất dễ bị chế giễu quá nhiều và che giấu các lỗi thực sự. Bạn sẽ không muốn làm quá mức với phương pháp này:các thử nghiệm đầy expectsstubs khó đọc và khó nghĩ.

Thử nghiệm giả mạo:cách tiếp cận ưa thích của tôi

Nếu lúc nào bạn cũng chế nhạo hoặc khai thác các phương pháp giống nhau trên cùng một đối tượng, bạn có thể quảng cáo chế độ giả của mình cho các đối tượng chính thức (đôi khi được gọi là thử nghiệm giả ), như thế này:

def test_billed_full_amount_minus_discount
  test_payment_provider = TestPaymentProvider.new # A fake payment provider
  cart = Cart.new(items, discount: 30, provider: test_payment_provider)
  cart.checkout!

  assert_equal items.sum(:&price) * 0.7, test_payment_provider.total_charges
end

Hàng giả rất tuyệt:

  • Giả mạo của bạn có thể theo dõi trạng thái bên trong của nó

    Kẻ giả mạo có thể có các thông báo xác nhận tùy chỉnh và các chức năng trợ giúp giúp bạn viết các bài kiểm tra dễ dàng hơn, chẳng hạn như total_charges trong ví dụ trên.

  • Là một đối tượng chính thức, bạn được hỗ trợ thêm về trình chỉnh sửa và ngôn ngữ

    Nếu bạn đang sử dụng trình chỉnh sửa hỗ trợ nó, bạn có thể tự động hoàn thành, tài liệu nội tuyến và những thứ khác mà bạn sẽ không mắc phải các phương pháp riêng lẻ với Mocha. Bạn cũng sẽ nhận được các xác thực tốt hơn, xử lý ngoại lệ và bất cứ điều gì khác mà bạn muốn xây dựng thành giả mạo của mình.

  • Nếu bạn sử dụng dịch vụ giả trong chế độ phát triển, bạn không cần phải có kết nối với dịch vụ thực

    Bạn có thể viết ứng dụng của mình trên xe buýt, bạn không cần phải có một rừng dịch vụ làm cạn pin máy tính xách tay của mình và bạn có thể thiết lập các dịch vụ giả mạo này để trả lại dữ liệu bạn cần để làm việc thông qua các trường hợp phức tạp mà không cần nhiều thiết lập.

  • Những đối tượng này có thể được sử dụng bên ngoài các thử nghiệm của bạn

    Đây có lẽ là phần yêu thích của tôi về hàng giả. Bạn có thể có một bản ghi logclient cho cả dịch vụ của bên thứ 3 và giả mạo của bạn, được hỗ trợ bởi một mảng trong bộ nhớ. Sau đó, bạn có thể kết xuất nội dung của khay này trong chế độ xem quản trị trên trang web của bạn , giúp việc xác minh rằng bạn đang ghi lại những gì bạn nghĩ là mình đang ghi dễ dàng hơn nhiều.

Bạn có thể làm điều gì đó như sau:

  fake_backend = FakeBackend.new
  LoggingService.backends = [RealBackend.new, fake_backend]
  LoggingService.debug("TEST MESSAGE PLEASE IGNORE")
  fake_backend.messages.first # => [:debug, "TEST MESSAGE PLEASE IGNORE"]

Viết giả mạo tốn nhiều công sức hơn so với viết ra các phương pháp riêng lẻ, nhưng với việc thực hành, bạn sẽ không mất quá một hoặc hai giờ để tạo ra một bản giả hữu ích. Nếu bạn xây dựng một cái hữu ích cho người khác, hãy chia sẻ nó! Tôi đã xây dựng đơn vị thời gian dài và rất nhiều người vẫn sử dụng nó cho đến ngày nay.

Tôi vẫn làm cách nào để đưa những đối tượng này vào?

Bạn sẽ phải kiểm tra các đối tượng của mình để nói chuyện với các fakessomehow này. May mắn thay, Ruby rất dễ lạm dụng nên việc tiêm hàng giả không khó.

Nếu bạn kiểm soát API của đối tượng đang được thử nghiệm, tốt nhất bạn nên thêm tham số adefault, thuộc tính hoặc tùy chọn phương thức khởi tạo để bạn thiết lập giả mạo của mình:

class Card
  attr_reader :provider
  def initialize(items, options={})
    @provider = options.fetch(:provider) { RealProvider.new }
  end
end

Điều này rõ ràng khi bạn đang nói chuyện với dịch vụ thực và giúp bạn có thêm khả năng linh hoạt sau này.

Nếu bạn không kiểm soát đối tượng hoặc không muốn thêm tham số ngoại suy, bạn luôn có thể phổ biến bản vá:

# if in test mode
Card.class_eval do
  def provider
    @provider ||= TestProvider.new
  end
end

Nó xấu hơn trong thử nghiệm, nhưng sạch hơn trong môi trường không sử dụng đồ giả.

Bắt đầu tạo giả mạo của riêng bạn ngay bây giờ

Việc xây dựng hàng giả trở nên dễ dàng hơn khi thực hành, vì vậy bạn nên thử ngay:

  • Tìm một bài kiểm tra nói chuyện với một dịch vụ bên ngoài. Các bài kiểm tra sẽ thất bại nếu bạn ngắt kết nối Internet là những ứng cử viên sáng giá.
  • Tìm ra đối tượng nào thực sự thực hiện giao tiếp và điều gì gọi mã của bạn thực hiện với đối tượng đó.
  • Tạo một bản sao gần như trống của lớp đối tượng đó và yêu cầu nó ghi lại các lệnh gọi bạn thực hiện cho một mảng.
  • Thêm một phương thức vào giả của bạn để trả về danh sách các cuộc gọi đã thực hiện.
  • Hoán đổi đối tượng thực bằng đối tượng giả mới và viết một số xác nhận chống lại các lệnh gọi mà mã của bạn thực hiện.

Nếu bạn thử, hãy cho tôi biết kết quả như thế nào!

Với những kỹ thuật này, sẽ không lâu nữa cho đến khi bạn có thể chế ngự các tương tác kỳ lạ nhất giữa ứng dụng của bạn và ứng dụng mới. Một sơ khai đơn giản ở đúng nơi sẽ giúp bạn tự tin gửi mã đã được kiểm tra kỹ lưỡng của mình.