Is there a way to create a mock class, as opposed to a mock object, with phpunit? I'm looking for a way to do dependency injection without having to explicitly pass every object a class might need to work with in the constructor (or wherever). Something that will return "true" for all of these cases:
public function testAAAA()
{
$foo = $this->getMock('foo', array('bar'));
var_dump(class_exists('foo', false));
var_dump(method_exists('foo', 'bar'));
var_dump(method_exists($foo, 'bar'));
}
This prints:
bool(true)
bool(false)
bool(true)
indicating that while it did successfully create a fake 'foo' class it did not bind a 'bar' method to it.
I am using phpunit 3.7.5.
I suspect that you don't actually want to do this (as you can disable constructors and so on with PHPUnit's mockbuilder, see the docs ), but assuming you do want or need to, this should do the trick:
$foo = $this->getMockBuilder('nonexistant')
->setMockClassName('foo')
->setMethods(array('bar'))
->getMock();
var_dump(class_exists('foo', false));
var_dump(method_exists('foo', 'bar'));
var_dump(method_exists($foo, 'bar'));
$cls = new ReflectionClass('foo');
var_dump($cls->hasMethod('bar'));
I'm honestly not sure about the specifics of why you need to specify different names (nonexistant and foo) above, but it seems to have to do with PHPUnit's behavior when the class being mocked doesn't exist yet, and having setMockClassName generate a class extending that class. Or Something. It's probably effectively working around a bug/edge-case -- this is odd usage of the library. You should be able to do the same thing through the getMock function alone, it's just uglier.
As an aside, it sounds like you should probably get familiar with php's reflection capabilities. It's not the most powerful reflection library out there, but it's pretty nice. I've used it to generate meta-information about required and optional fields for a class based on their constructor arguments and properties for a "model" library, where that meta-information is used to generate forms that accept the correct types of values. That is, generate typed forms without instances of the class the form is for, and without hand-writing a stupid amount of code -- it's about 100 lines in all for the entire feature. Obviously I don't know what you're trying to do, but from the small amount of info in your post, I'd guess it's closer to that type of meta-thing than not.
Related
I need to mock CurrencyEnum by overload it, but it's not the end becouse i need to add interface to this mock.
This doesn't work:
Mockery::mock('overload:'.CurrencyEnum::class);
Error: (..) must be an instance of \BaseCurrency, instance of \CurrencyEnum given.
I looked at Mockery\Container::mock and I dont't have idea how to do it.
In example I want to test TestingClass::first() method
class CurrencyEnum implements BaseCurrency
{
/* methods */
}
class TestingClass
{
public function first(string $currencySymbol)
{
$abc = 'some_string';
return $this->second($abc, new CurrencyEnum($currencySymbol));
}
private function second(string $abc, BaseCurrency $currency)
{
/* code */
}
}
The overload method works by intercepting the autoload mechanism: it registers an autoloader for the overloaded class, loading the mocked version of the class instead of the original.
By default, it does not add many things to the mocked class. You can, however, configure just about anything you may need.
Usually, implementing one or more interfaces can be done by providing a comma-separated list of fully qualified names, the first one being the class:
$mock = Mockery::mock('MyClass, MyInterface, OtherInterface');
Due to the way that the Mockery::mock method is set up, this will not work. (The author apologises in the source code)
However, we can pass the interface(s) as second argument to the mock method:
Mockery::mock('overload:'.CurrencyEnum::class, BaseCurrency::class);
This will cause the MockConfigurationBuilder to add BaseCurrency as target; since it's an interface it will make the mock implement the interface.
An alternative notation of the above would be to use the builder directly:
Mockery::mock(
(new MockConfigurationBuilder())
->setInstanceMock(true)
->setName(CurrencyEnum::class)
->addTarget('stdClass')
->addTarget(BaseCurrency::class)
)
Having said that, it's a notoriously bad practice to mock things like enums and value objects. Why not just use the actual CurrencyEnum? Something as simple as a currency code does not quite warrant mocking at all. There's probably a structural improvement to make, which would simultaneously add tons of value to your tests and make them simpler to read.
Need a bit of help using Mockery - I want to overload a class, which is created using new HelperUtil() in a method.
Using Mockery overload I can do this, but it is leaving me with an empty shell class. Which I then appear to have to create all methods that are called. Is there a way to create a overloaded full mock, and then change just one method?
$mock = \Mockery::mock('overload:'.HelperUtil::class);
$mock->shouldReceive('content')->andReturnUsing(function() {
return 'different content';
});
thanks
edit:
I think i want to do:
$mock = \Mockery::mock('overload:'.HelperUtil::class)->shouldDeferMissing();
$mock->shouldReceive('content')->andReturnUsing(function() {
return 'different content';
});
But that still dosnt work =(
There is an interesting discussion about it on GitHub
shouldIgnoreMissing and shouldDeferMissing (and other such flags
present and future) do work, but not on the mock, but on the instance
mock.
Sounds confusing, but it's because of internals.
When you do a m::mock('overload:Foo'); mockery goes and creates a new
class called Foo based on the Mock.php "template". And that template
has the _mockery_ignoreMissing flag set to false by default.
Once the mock method gets to the end, it creates an overloaded Foo
object and returns it to us. The overloaded Foo class is also
available to instantiate new Foo objects.
Calling $m->shouldIgnoreMissing() sets the ignore missing flag on the
object that was returned by the mock method.
Calling new Foo() creates a new instance of the Foo object that has
the Mock.php templates default of false for _mockery_ignoreMissing.
If you want the flag set to true on the new instance, you need to call
shouldIgnoreMissing() on that instance, and not on $m.
As I see, feature "should ignore missing on instance mocks" has been completed, so the best you can do is
$mock = \Mockery::mock('overload:'.HelperUtil::class)->shouldIgnoreMissing();
I don't see shouldDeferMissing has been done yet for overload.
Of course, as a workaround, you might consider creating a mock and injecting it.
PHPUnit's getMock($classname, $mockmethods) creates a new object based on the given class name and lets me change/test the behavior of the methods I specified.
I long for something different; it's changing the behavior of methods of an existing object - without constructing a new object.
Is that possible? If yes, how?
When thinking about the problem I came to the conclusion that it would be possible by serializing the object, changing the serialized string to let the object be instance of a new class that extends the old class plus the mocked methods.
I'd like some code for that - or maybe there is such code already somewhere.
While it would certainly be possible to create the to-be-mocked object again, it's just too complicated to do it in my test. Thus I don't want to do that if I don't really really really have to. It's a TYPO3 TSFE instance, and setting that up once in the bootstrapping process is hard enough already.
I know this answer is rather late, but I feel for future viewers of this question there now exists a simpler solution (which has some drawbacks, but depending on your needs can be much easier to implement). Mockery has support for mocking pre-existing objects with what they call a "proxied partial mock." They say that this is for classes with final methods, but it can be used in this case (although the docs do caution that it should be a "last resort").
$existingObjectMock = \Mockery::mock($existingObject);
$existingObjectMock->shouldReceive('someAction')->andReturn('foobar');
It acts by creating a proxy object which hands all method calls and attribute gets/sets to the existing object unless they are mocked.
It should be noted, though, that the proxy suffers from the obvious issue of failing any typechecks or typehints. But this can be usually avoided, because the $existingObject can still be passed around. You should only use the $existingObjectMock when you need the mock capabilities.
Not all pre-existing code can be tested. Code really needs to be designed to be testable. So, while not exactly what you're asking for, you can refactor the code so that the instantiation of the object is in a separate method, then mock that method to return what you want.
class foo {
function new_bar($arg) { return new bar($arg); }
function blah() {
...
$obj = $this->new_bar($arg);
return $obj->twiddle();
}
}
and then you can test it with
class foo_Test extends PHPUnit_Framework_TestCase {
function test_blah() {
$sut = $this->getMock('foo', array('new_bar', 'twiddle'));
$sut->expects($this->once())->method('new_bar')->will($this->returnSelf());
$sut->expects($this->once())->method('twiddle')->will($this->returnValue('yes'));
$this->assertEquals('yes', $sut->blah());
}
}
Let me start of by saying: Welcome to the dark side of unit testing.
Meaning: You usually don't want to do this but as you explained you have what seems to be a valid use case.
runkit
What you can do quite easily, well not trivial but easier than changing your application architecture, is to change class behavior on the fly by using runkit
runkit_method_rename(
get_class($object), 'methodToMock', 'methodToMock_old'
);
runkit_method_add(
get_class($object), 'methodToMock', '$param1, $param2', 'return 7;'
);
runkit::method_add
and after the test to a method_remove and the rename again. I don't know of any framework / component that helps you with that but it's not that much to implement on your own in a UglyTestsBaseTest extends PHPUnit_Framework_TestCase.
Well...
If all you have access to is a reference to that object (as in: The $x in $x = new Foo();) i don't know of any way to say: $x, you are now of type SomethingElse and all other variables pointing to that object should change too.
I'm going to assume you already know things like testing your privates but it doesn't help you because you don't have control over the objects life cycle.
The php test helpers extension
Note: the Test-Helper extension is superseded by https://github.com/krakjoe/uopz
What also might help you out here is: Stubbing Hard-Coded Dependencies using the php-test-helpers extension that allows you do to things like Intercepting Object Creation.
That means while your application calls $x = new Something(); you can hack PHP to make it so that $x then contains an instance of YourSpecialCraftedSomething.
You might create that classing using the PHPUnit Mocking API or write it yourself.
As far as i know those are your options. If it's worth going there (or just writing integration / selenium tests for that project) is something you have to figure out on your own as it heavily depends on your circumstances.
I am trying to test a class that manages data access in the database (you know, CRUD, essentially). The DB library we're using happens to have an API wherein you first get the table object by a static call:
function getFoo($id) {
$MyTableRepresentation = DB_DataObject::factory("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
...you get the idea.
We're trying to test this method, but mocking the DataObject stuff so that (a) we don't need an actual db connection for the test, and (b) we don't even need to include the DB_DataObject lib for the test.
However, in PHPUnit I can't seem to get $this->getMock() to appropriately set up a static call. I have...
$DB_DataObject = $this->getMock('DB_DataObject', array('factory'));
...but the test still says unknown method "factory". I know it's creating the object, because before it said it couldn't find DB_DataObject. Now it can. But, no method?
What I really want to do is to have two mock objects, one for the table object returned as well. So, not only do I need to specify that factory is a static call, but also that it returns some specified other mock object that I've already set up.
I should mention as a caveat that I did this in SimpleTest a while ago (can't find the code) and it worked fine.
What gives?
[UPDATE]
I am starting to grasp that it has something to do with expects()
I agree with both of you that it would be better not to use a static call. However, I guess I forgot to mention that DB_DataObject is a third party library, and the static call is their best practice for their code usage, not ours. There are other ways to use their objects that involve constructing the returned object directly. It just leaves those darned include/require statements in whatever class file is using that DB_DO class. That sucks because the tests will break (or just not be isolated) if you're meanwhile trying to mock a class of the same name in your test--at least I think.
When you cannot alter the library, alter your access of it. Refactor all calls to DB_DataObject::factory() to an instance method in your code:
function getFoo($id) {
$MyTableRepresentation = $this->getTable("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
function getTable($table) {
return DB_DataObject::factory($table);
}
Now you can use a partial mock of the class you're testing and have getTable() return a mock table object.
function testMyTable() {
$dao = $this->getMock('MyTableDao', array('getMock'));
$table = $this->getMock('DB_DataObject', ...);
$dao->expects($this->any())
->method('getTable')
->with('mytable')
->will($this->returnValue($table));
$table->expects...
...test...
}
This is a good example of a dependency in your code - the design has made it impossible to inject in a Mock rather than the real class.
My first suggestion would be to try and refactor the code to use an instance rather than a static call.
What's missing (or not?) from your DB_DataObject class is a setter to pass a prepared db object before calling the factory method. That way you can pass a mock or a custom db object (with the same interface) should the need arise.
In your test setup:
public function setUp() {
$mockDb = new MockDb();
DB_DataObject::setAdapter($mockDb);
}
The factory() method should return the mocked DB instance. If it's not already integrated into your class, you will probably have to refactor the factory() method as well to make it work.
Are you require/including the class file for DB_DataObject in your test case? If the class doesn't exist before PHPUnit tries to mock the object you can get errors like this.
With PHPUnit MockFunction extension plus runkit you can also mock static methods. Be careful, because it's monkey patching and therefore should only be used in extreme cases. Does not substitute good programming practices.
https://github.com/tcz/phpunit-mockfunction
I currently have a method within my class that has to call other methods, some in the same object and others from other objects.
class MyClass
{
public function myMethod()
{
$var1 = $this->otherMethod1();
$var2 = $this->otherMethod2();
$var3 = $this->otherMethod3();
$otherObject = new OtherClass();
$var4 = $otherObject->someMethod();
# some processing goes on with these 4 variables
# then the method returns something else
return $var5;
}
}
I'm new to the whole TDD game, but some of what I think I understood to be key premises to more testable code are composition, loose coupling, with some strategy for Dependency Injection/Inversion of Control.
How do I go about refactoring a method into something more testable in this particular situation?
Do I pass the $this object reference to the method as a parameter, so that I can easily mock/stub the collaborating methods? Is this recommended or is it going overboard?
class MyClass
{
public function myMethod($self, $other)
{
# $self == $this
$var1 = $self->otherMethod1();
$var2 = $self->otherMethod2();
$var3 = $self->otherMethod3();
$var4 = $other->someMethod();
# ...
return $var5;
}
}
Also, it is obvious to me that dependencies are a pretty big deal with TDD, as one has to think about how to inject a stub/mock to the said method for tests. Do most TDDers use DI/IoC as a primary strategy for public dependencies? at which point does it become exaggerated? can you give some pointers to do this efficiently?
These are some good questions... let me first say that I do not really know JS at all, but I am a unit tester and have dealt with these issues. I first want to point out that JsUnit exists if you are not using it.
I wouldn't worry too much about your method calling other methods within the same class... this is bound to happen. What worries me more is the creation of the other object, depending on how complicated it is.
For example, if you are instantiating a class that does all kinds of operations over the network, that is too heavy for a simple unit test. What you would prefer to do is mock out the dependency on that class so that you can have the object produce the result you would expect to receive from its operations on the network, without incurring the overhead of going on the network: network failures, time, etc...
Passing in the other object is a bit messy. What people typically do is have a factory method to instantiate the other object. The factory method can decide, based on whether or not you are testing (typically via a flag) whether or not to instantiate the real object or the mock. In fact, you may want to make the other object a member of you class, and within the constructor, call the factory, or make the decision right there whether or not to instantiate the mock or the real thing. Within the setup function or within your test cases you can set special conditions on the mock object so that it will return the proper value.
Also, just make sure you have tests for your other functions in the same class... I hope this helps!
Looks like the whole idea of this class is not quite correct. In TDD your are testing classes, but not methods. If a method has it own responsibility and provides it's own (separate testable) functionality it should be moved to a separate class. Otherwise it just breaks the whole OOP encapsulation thing. Particularly it breaks the Single Responsibility Principle.
In your case, I would extract the tested method into another class and injected $var1, $var2, $var3 and $other as dependencies. The $other should be mocked, as well any object which tested class depends on.
class TestMyClass extends MyTestFrameworkUnitTestBase{
function testMyClass()
{
$myClass = new MyClass();
$myClass->setVar1('asdf');
$myClass->setVar2(23);
$myClass->setVar3(78);
$otherMock = getMockForClassOther();
$myClass->setOther($otherMock);
$this->assertEquals('result', $myClass->myMethod());
}
}
Basic rule I use is: If I want to test something, I should make it a class. This is not always true in PHP though. But it works in PHP in 90% of cases. (Based on my experience)
I might be wrong, but I am under the impression that objects/classes should be black boxes to their clients, and so to their testing clients (encapsulating I think is the term I am looking for).
There's a few things you can do:
The best thing to do is mock, here's one such library: http://code.google.com/p/php-mock-function
It should let you mock out only the specific functions you want.
If that doesn't work, the next best thing is to provide the implementation of method2 as a method of an object within the MyClass class. I find this one of the easier methods if you can't mock methods directly:
class MyClass {
function __construct($method2Impl) {
$this->method2Impl = $method2Impl;
}
function method2() {
return $this->method2Imple->call();
}
}
Another option is to add an "under test" flag, so that the method behaves different. I don't recommend this either - eventually you'll have differing code paths and with their own bugs.
Another option would be to subclass and override the behaviors you need. I -really- don't suggest this since you'll end up customizing your overridden mock to the point that it'll have bugs itself :).
Finally, if you need to mock out a method because its too complicated, that can be a good sign to move it into its own object and use composition (essentially using the method2Impl technique i mentioned above).
Possibly, this is more a matter of single responsibility principle being violated, which is feeding into TDD issues.
That's a GOOD thing, that means TDD is exposing design flaws. Or so the story goes.
If those methods are not public, and are just you breaking apart you code into more digestable chunks, honestly, I wouldn't care.
If those methods are public, then you've got an issue. Following the rule, 'any public method of a class instance must be callable at any point'. That is to say, if you're requiring some sort of ordering of method calls, then it's time to break that class up.