dashbitco / mox

Mocks and explicit contracts in Elixir
1.35k stars 77 forks source link

Fallback to stub when there is a FunctionClauseError in expect #42

Closed dsdshcym closed 6 years ago

dsdshcym commented 6 years ago

I think this feature is useful when we want to focus on checking only one specific message was sent to the mock while ignoring all the other messages.

For example, the function I'm working on right now would send multiple websocket events to different topics, and in each unit test for this function, I pass a mocked Phoenix Endpoint to it and call expect on each type of event.

With the current implementation of Mox, I need to specify several expects and the order needs to match the exactly same order as broadcast/3 would be called

test "broadcasts to topic_a" do
  expect(EndpointMock, :braodcast, fn "topic_a:room", _, _ -> nil end)
  expect(EndpointMock, :braodcast, fn _, _, _ -> nil end)

  WebSocket.send(:event, params, EndpointMock)
end

test "broadcasts to topic_b" do
  expect(EndpointMock, :braodcast, fn _, _, _ -> nil end)
  expect(EndpointMock, :braodcast, fn "topic_b:room", _, _ -> nil end)

  WebSocket.send(:event, params, EndpointMock)
end

What I want is something like the following snippet:

test "broadcasts to topic_a" do
  stub(EndpointMock, :broadcast, fn _, _, _ -> nil end)
  expect(EndpointMock, :braodcast, fn "topic_a:room", _, _ -> nil end)

  WebSocket.send(:event, params, EndpointMock)
end

test "broadcasts to topic_b" do
  stub(EndpointMock, :broadcast, fn _, _, _ -> nil end)
  expect(EndpointMock, :braodcast, fn "topic_b:room", _, _ -> nil end)

  WebSocket.send(:event, params, EndpointMock)
end
josevalim commented 6 years ago

Hi @dsdshcym! I think that, if something is part of your contract, it is important to assert on how many times it has been invoked. We may potentially change this in the future but it is not in the plans right now.

Thanks for opening the issue and sorry for the delayed response.

dsdshcym commented 6 years ago

@josevalim Thanks for the reply!

I totally agree with that we need to assert on how many times a function should be called.

But this issue is not about that, it's about the order a function gets called.

I think our test setups/expectations should not be coupled to the order of how we call a function.

In the example I gave above: I need to expect broadcasting to topic_a first, otherwise the test would fail.

And I don't want to expect both topic_a and topic_b in the same test case because they are two completely separate concerns.

There might be other ways to fix this issue, other than falling back to stub. Apologize for any misunderstanding caused by the title.