Reputation: 39
I am trying to mock a method that should have a datetime object of a set value passed to it
$mock->shouldReceive('setDatetime')
->with($datetime)
->once;
I'm fairly new to mockery but I don’t understand how 'with' is working. If $datetime is the exact object that is being passed into 'setDatetime' then it satisfies the condition perfectly. If it is a datetime object, but not exactly same object, i.e. all the values are the same, but it is a different instantiated DateTime object, then it doesn't work. The Datetime object I'm currently passing to setDatetime has been altered using DateInterval. Is there anyway i can test whether the datetime object being received has the same values even if it isn't the same object.
Upvotes: -1
Views: 1433
Reputation: 512
I had an issue when I wanted to check only one of couple arguments, and one of the arguments were expected to be \DateTime, but I was not particulary interested in that value, I needed to check another param and return particular data for this argument, and this is what I did:
$dataRepository->shouldReceive('someMethod')
->withArgs(function (...$args)) {
// for example, $args[3] could be \DateTime, but I don't care about it
return $args[1] = 99,
})
->andReturn([
new dataObject(99, 1),
new dataObject(99, 2),
new dataObject(99, 3),
]);
$dataRepository->shouldReceive('someMethod')
->withArgs(function (...$args)) {
// for example, $args[3] could be \DateTime, but I don't care about it
return $args[1] = 101,
})
->andReturn([
new dataObject(101, 1),
new dataObject(101, 2),
new dataObject(101, 5),
]);
Upvotes: 0
Reputation: 31
Another solution would be using the \Hamcrest\Matchers::equalTo
. This way you explicitly set the comparison to ==
(equals) instead of ===
(strict). You will only need this for objects since for primitives it automatically checks for ==
comparison as a fallback.
Example:
$mock->shouldReceive('setDatetime')
->with(\Hamcrest\Matchers::equalTo($datetime))
->once;
The documentation writes the following:
The most common matcher is the with() matcher:
It tells mockery that it should receive a call to the foo method with the integer 1 as an argument. In cases like this, Mockery first tries to match the arguments using === (identical) comparison operator. If the argument is a primitive, and if it fails the identical comparison, Mockery does a fallback to the == (equals) comparison operator.
When matching objects as arguments, Mockery only does the strict === comparison, which means only the same $object will match.
Source: http://docs.mockery.io/en/latest/reference/argument_validation.html
Upvotes: 3
Reputation: 1125
This is possible by giving a closure to your with().
To give the closure to the with function Mockery gives you a Closure matcher
Mockery\Matcher\Closure
This class will take a closure and use it to match the value you get.
How you would implement this is like this:
$expectedDateTime = new DateTime();
$mock->shouldReceive('setDatetime')
->with
(new Closure(
function($datetime) use ($expectedDateTime) {
return $datetime->getTimestamp() === $expectedDateTime->getTimeStamp()
}
)
)->once;
The epextedDateTime is of course the date time that it should be but for example purposes added here. You can also create that DateTime object in the closure if you dont need it outside the assertion, you won't need the use in the closure then.
And of course you can check/assert whatever you want in the closure as an example I did the easiest test of checking if the timestamps are equal.
Upvotes: 0