Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to allow call to original method? #332

Closed
loren-osborn opened this issue May 5, 2017 · 6 comments · Fixed by #546
Closed

How to allow call to original method? #332

loren-osborn opened this issue May 5, 2017 · 6 comments · Fixed by #546

Comments

@loren-osborn
Copy link

I suspect that I'm running into this issue as I'm trying to mix a wrapper that should probably be injected into the class that's using it, but I distinctly remember mocking some methods and not others in PHPUnit's mocking system some years ago, and would like to know how to do this in Prophecy.

In this situation, I have a class with four methods:

  • Two methods simply wrap native PHP functions and definitely need to be mocked.
    • In this particular case I'm confident that I've been able to test that these methods do map correctly to the intended functions, though I can think of many similar situations where this wouldn't be the case.
  • One is totally stateless, and simply transforms its input, so I can test it fully without any mocking. Given that I control its input, I'm happy to mock or not mock this method, Whatever is most convenient.
  • The last method is the one I am trying to write tests for. It calls the other three methods.

How do I write tests for the last method, with the first two or three methods mocked. I tried using $objProph->methodToTest('argValue')->shouldBeCalled();, but the reveal()ed object's method always returned NULL and I suspect never called the parent class method.

I am aware that I can simply put the first two methods in their own class (and perhaps I should do that) and pass this object to the original class's constructor. Then I could easily mock the injected object without worrying about mocking for the other two methods, but this seems a bit cumbersome.

Is there currently a way in Prophecy to mock some methods and not others in a class? I thought these hybridized object classes were called "test doubles" but I may have my terminology wrong.

Please advise, Thanks.

@stof
Copy link
Member

stof commented May 5, 2017

Partial mocking is something we explicitly decided to never support in Prophecy, as needing them is generally a sign that your class violates SRP. And one of the goal of Prophecy (and of PhpSpec in general) is to push you away from bad architectures.

If you cannot refactor your code, use a different mocking library for this case (the old PHPUnit_MockObject system supports partial mocks, and is still available in PHPUnit in parallel of Prophecy)

@loren-osborn
Copy link
Author

It may be helpful to add something about this a bit more explicitly to the documentation. Perhaps define and describe partial mocks, and why they're unsupported. This may save users like me hours picking through the code trying to untangle how to make prophecy spit out a partial double.

Based on my description, does the injected wrapper sound like a reasonable design? I generally avoid adding code paths in production code exclusively used by test code, but unless I force the production caller to always inject the wrapper object, (or forcing them to use DI container) injecting the wrapper class at run time will only be used by test code. Normally, I'd override the accessor to the wrapper object with the mocked object in a partial double. What do you recommend as an alternative?

@loren-osborn
Copy link
Author

(I suppose I could simply make the wrapper object property public, and set it to the mock in my test code)

@stof
Copy link
Member

stof commented May 5, 2017

you can make the wrapper an optional constructor argument (instantiating one automatically in the constructor if not provided)

@loren-osborn
Copy link
Author

Yes, but that still makes not constructing it when provided a testing-specific code path. :-(

sandrokeil pushed a commit to sandrokeil/service-bus-symfony-bundle that referenced this issue Jun 20, 2017
basz pushed a commit to basz/micro-cli that referenced this issue Nov 2, 2018
basz pushed a commit to basz/standard-projections that referenced this issue Nov 2, 2018
@danepowell
Copy link
Contributor

I just ran into the same issue, and while I suspected that the ultimate solution was to rearchitect the affected class, I would have really appreciated seeing this called out in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants