-
Notifications
You must be signed in to change notification settings - Fork 241
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
Can I mock singletons? #471
Comments
Well, you won't be able to mock the singleton directly, as you would need a way to instantiate the double object and to inject it in the |
No, there's no sensible way to do that The important thing about a singleton is that it is enforcing the constraint that there's a single instance - the global availability is an unfortunate abused side-effect of the pattern. You can refactor your objects to take the singleton in their constructor as part of testing |
Like Reflection? Indeed, I'm not sure how to approach that if Prophecy don't plan to support it... 🤔
Yes, that's exactly what I'm doing. The codebase is WordPress, for an enterprise plugin that's been around for 10 years now. Getting rid of singletons is just not an option. We have now a DI container in place, and I'm injecting the dependencies in the constructor, Singletons included. That's where the "Can I mock a singleton" question comes in. Since I'm feeding it in the constructor, I would like to mock it to test the class that takes it as a dependency. Thanks for the help so far. |
You can certainly mock it then; you won't need to call getInstance() on the mock because you already have the instance |
Hmm, I don't have the instance because I can't call For instance: class Foo {
private $singleton;
public function __construct( Singleton $singleton ) {
$this->singleton = $singleton;
}
public function do_something() {
if ( ! $this->singleton->hasCap() ) {
// Don't do something
return false;
}
// Do something
return true;
}
} class FooTest {
public function should_do_something_if_has_caps() {
$singleton = $this->prophesize(Singleton::class);
$singleton->hasCap()->willReturn( true );
$foo = new Foo( $singleton->reveal() );
$this->assertTrue( $foo->do_something() );
}
public function should_do_something_if_does_not_has_caps() {
$singleton = $this->prophesize(Singleton::class);
$singleton->hasCap()->willReturn( false );
$foo = new Foo( $singleton->reveal() );
$this->assertFalse( $foo->do_something() );
}
} I'm pretty sure (I've tried it yesterday but can't quite remember), that I can't test |
Ah "can't mock private constructor" sounds like a more specific issue |
Hello,
Can I mock a class with a protected/private constructor and a public static method
::instance()
? (The classic Singleton setup)Eg:
I know I shouldn't be using singletons anyway, but this is what the code I'm trying to test looks like.
Thanks.
The text was updated successfully, but these errors were encountered: