Test::...Server(3pm)

πŸ“¦ version 0.0.1, in opensuse-leap 16.0

πŸ¦‹ Test::...Server(3pm) πŸ¦‹

okay bestie so this page lives in the Perl docs under User Contributed Perl Documentation, and the module is Test::HTTP::MockServer β€” yes, the header truncates it to Test::...Server(3pm), that's just how the man page renders it, don't panic πŸ’–


✨ NAME ✨

Test::HTTP::MockServer β€” implement a mock HTTP server for use in tests πŸŽ€


✨ SYNOPSIS ✨

  use Test::HTTP::MockServer;

  my $server = Test::HTTP::MockServer->new();
  my $url = $server->url_base();
  # inject $url as the config for the remote http service.

  my $handle_request_phase1 = sub {
      my ($request, $response) = @_;
      ...
  };
  $server->start_mock_server($handle_request_phase1);
  # run your tests against $handle_request_phase1
  $server->stop_mock_server();

  my $handle_request_phase2 = sub {
      my ($request, $response) = @_;
      ...
  };
  $server->start_mock_server($handle_request_phase2);
  # run your tests against $handle_request_phase2
  $server->stop_mock_server();

πŸ’… DESCRIPTION πŸ’…

So here's the situation, bestie 😭 sometimes you're writing a test and you literally cannot do dependency injection on the type of transport some API uses. Like, the code is gonna use actual HTTP, periodt. The only thing you get to control is the host and port it connects to. That's it. That's the whole vibe.

This class is your little superhero for exactly that 🫢 it gives you a simple way to mock the service being called. How? By binding to a random port on localhost and letting you inspect which port that ended up being πŸ‘€ Using a random port is iconic because it means this whole thing works for tests running in parallel on the same host πŸ”₯

The socket gets bound and listened on the main test process, so the lifetime of the connection is defined by the lifetime of the test itself. Very main character energy ✨

And since the socket is already bound and listened to, the two control methods (start_mock_server and stop_mock_server) only fork for the accept call. Which means β€” and this is the good part β€” it's totally safe to call start and stop several times during one test in order to change the expectations of the mocked code 🌈

That gives you the ability to easily configure the mock server's expectations across each step of your test case πŸŽ€ On the other hand (balance, queen), it also means no state is shared between the code running in the mock server and the test code. Just so you know πŸ’€


🧚 METHOS 🧚

(not me β€” the original page really spells it like that, we're keeping it, iykyk)

  • new() β€” creates a new MockServer object ✨
  • bind_mock_server() β€” finds a random available port, binds to it and listens on it. This is what lets you peek at what the mock url of the portal will be before the server forks to start. And if that random port is already in use? It just keeps trying until it finds one that works πŸ’ͺ
  • host() β€” returns the host the mock server is binding to. It'll call bind_mock_server for you if that hasn't been initialized yet. The current version always binds to 127.0.0.1 🏠
  • port() β€” returns the port the mock server is bound and listening to. It'll call bind_mock_server if that wasn't initialized yet πŸ”Œ
  • base_url() β€” returns the url to be used as the base url for requests into the mock server. It'll bind_mock_server if that wasn't initialized yet 🌸
  • start_mock_server($request_processor) β€” this will bind_mock_server if that wasn't initialized yet, then fork to accept connections πŸ“

And to make it easier for state to propagate across different requests in your mock implementation, there will only be one connection at a time, and every request in that connection gets handled serially ⭐

  • stop_mock_server() β€” kills the server running in the background, but it will not unbind the socket. Which means you can just call start_mock_server again with a different request_processor and the same url will be preserved πŸ‘‘

πŸ’œ THE REQUEST PROCESSOR πŸ’œ

The request processor is that code reference you send as an argument to the start_mock_server call β€” it receives all the requests that come in via the socket πŸ“¬

Whenever a request is received, your code reference gets called with two arguments:

  • $request β€” an HTTP::Request object with the request as it was received πŸŽ€
  • $response β€” an HTTP::Response object that will be sent back. It's initialized with "200 OK" and no content ✨
πŸ’€ heads up bestie: if your code dies while processing a request, a "500 Internal Server Error" response will be generated. dramatic but fair.

Copyright 2016 Bloomberg Finance L.P.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


okay that's the whole page, no cap πŸ’… this is perl v5.42.0, dated 2021-04-16, and it's the Test::...Server(3pm) page β€” go forth and mock, queen πŸ‘‘πŸ¦‹

πŸ“¦ where this page comes from