How to properly use atLeastOnce method in Codeception\Util\Stub? - php

I'm using codeception for testing my PHP app, and there is a method I don't know how to use. It's called Stub::atLeastOnce() and, like Codeception's documentation of the Stub class says:
"Checks if a method has been invoked at least one time. If the number of invocations is 0 it will throw an exception in verify."
But when I try to use it, doesn't matter that I comment the call to User::getName() or not, the test passes.
My user class looks like this:
<?php
class User {
public function getName() {
return 'pepito';
}
public function someMethod() {
}
}
And my test method like this:
public function testStubUsage() {
// all methods that the stub impersonates must be, at least, defined
$user = Stub::make('User', array('getName' => Stub::atLeastOnce(function() { return 'Davert'; }), 'someMethod' => Stub::atLeastOnce('User::getName')));
$user->getName();
}
So, what is the usage of that function to make the test fail if User::getname() is never called?

The doc is not correct, you have to pass $this as third argument of Stub::make() for this to work properly:
public function testStubUsage() {
$user = Stub::make('User', array('getName' => Stub::atLeastOnce(function() { return 'Davert';}), 'someMethod' => function() {}), $this); // <- Here
$user->getName();
}

Related

Cannot mock partial Log facade in Laravel

I'm trying to mock laravel Log. This is my code:
public function test_process_verify_card()
{
Log::shouldReceive('error')->once();
Log::makePartial();
$class = new MyClass();
$class->myFunction();
}
This is MyClass look like:
class MyClass
{
public function __construct()
{
$this->logger = Logg::channel('test');
}
public function myFunction()
{
// ... some logic
$this->loggger->error('Errror!!');
}
}
When I run test this test case, it throw error
Call to a member function runningUnitTests() on null
at vendor/laravel/framework/src/Illuminate/Log/LogManager.php:568
I tried to debug this error by putting dd() in LogManager class
protected function parseDriver($driver)
{
$driver ??= $this->getDefaultDriver();
dd($this->app); // <--- This is my code
if ($this->app->runningUnitTests()) {
$driver ??= 'null';
}
return $driver;
}
But it show that $this->app is not null.
I've tried mock facade Date before and it works fine.
I want to test that myFunction executes logging action. Is this correct way to do it?
Update
I also tried to mock it through partialMock() function:
public function test_process_verify_card()
{
$this->partialMock(Logger::class, function (MockInterface $mock) {
$mock->shouldReceive('error')->once();
});
$class = new MyClass();
$class->myFunction();
}
But it still not works, it shows error:
Method error(<Any Arguments>) from Mockery_0_Illuminate_Log_Logger should be called
exactly 1 times but called 0 times.
at vendor/phpunit/phpunit/phpunit:98
I would believe the problem why this is not working, is as Log::channel returns a channel on the partial mock. Therefor the mocked instance never receive the error call.
In Mockery you can easily do chained calls, by using '->' in the shouldReceive() call.
Log::shouldReceive('channel->error')
->once()
->andReturn(null);

Wanna unit-test a function, but constructor gives error

I am trying to unit test a function which is in an entity class, and it is stored in my DB by the use of a constructor. Each time I am trying to test this function it is giving me that error
ArgumentCountError: Too few arguments to function App\Entity\Deal::__construct(), 0 passed in /var/www/html/casus/tests/dealsEntityFunctionsTest.php on line 10 and exactly 1 expected
It is obvious I think, but I am really new with unit testing and that stuff so I couldn't find the answer. Could you please help me?
My code is
class Deal
{
private bool $isNewToday
public function __construct($deal)
{
$this->isNewToday = $deal['is_new_today'];
}
public function getIsNewToday(): ?bool
{
return $this->isNewToday;
}
public function setIsNewToday(bool $isNewToday): self
{
$this->isNewToday = $isNewToday;
return $this;
}
}
And my unit test is
class test extends TestCase
{
public function testIsNewTodayIsTrue()
{
$deal = new Deal();
$deal->setIsForSale(true);
$this->assertTrue($deal->getIsForSale(), true);
}
}
As brombeer suggested, new Deal entity requires parameter.
This parameter looks like an array, with key 'is_new_today'. So, sth like this below should help with constructor error.
class test extends TestCase
{
public function testIsNewTodayIsTrue()
{
$deal = new Deal(['is_new_today' => true]);
$deal->setIsForSale(true);
$this->assertTrue($deal->getIsForSale(), true);
}
}
This has nothing to do with Unit Testing, or Symfony, or any of the other details you mentioned. You've defined something with a mandatory parameter, and then aren't passing that parameter.
Just like any function, the parameters to a constructor are mandatory unless you provide a default. And if you write code that assumes the parameter will have a particular format, you need to provide a value that meets that assumption.
So either pass the parameter every time you create the object, with whatever format the constructor expects:
$deal = new Deal(['is_new_today' => false]);
... or make it optional, and decide what should happen if it's not passed:
class Deal
{
private bool $isNewToday
public function __construct(?array $deal = null)
{
if ( isset($deal) ) {
$this->isNewToday = $deal['is_new_today'];
}
else {
$this->isNewToday = false;
}
}
}
Note that $isNewToday is defined as a non-nullable boolean, so you should always give it a value in the constructor, or an inline default, like private bool $isNewToday = false; Otherwise, you'll get "uninitialized value" errors if you try to read it. For that reason, the return type of ?bool on getIsNewToday() doesn't make sense - it can't return null, because $this->isNewToday can never be bool.

Calling php functions that have an instance as an argument

Ok so my question is, i have a Facebook call back function that I'm using. The callback function uses an instance as an argument facebookCallBack(LaravelFacebookSdk $fb)
The function works great,I'm using this in my auth controller in larvel , but now I want to reuse this function within the same controller something like $this>facebookReusableCallBack(LaravelFacebookSdk $fb)
I'm having issues ,i get this error facebookReusableCallBack() must be an instance of SammyK\LaravelFacebookSdk\LaravelFacebookSdk, none given.
here's a sample of my code:
public function facebookCallBack(LaravelFacebookSdk $fb) {
$this->facebookReusableCallBack();
}
public function facebookReusableCallBack() {
//All my code here
}
how can I reuse this function within my controller?
i've tried :
public function facebookCallBack(LaravelFacebookSdk $fb) {
$this->facebookReusableCallBack(LaravelFacebookSdk $fb);
}
but the argument doesn't get passed as an instance?
You don't need to define the type of a variable when you pass it in.
Method definition:
public function facebookReusableCallBack(LaravelFacebookSdk $fb) {
//some code
}
Execution within another method:
function myMethod() {
$var = new LaravelFacebookSdk();
$this->facebookReusableCallBack($var);
}
What you have done is define the type of the variable in your function definition (good) to force the type. However these are only needed in the definition.
So for your explicit example:
public function facebookCallBack(LaravelFacebookSdk $fb) {
$this->facebookReusableCallBack($fb);
}
Because $fb must be an instance of LaravelFacebookSdk when calling facebookCallBack it will be fine for facebookReusableCallBack.

Phpunit, how to test if method does "nothing"?

class Testme()
{
public function testMe ($a)
{
if ($a == 1)
{
throw new Exception ('YAY');
}
}
}
so its easy to test if it threw exception
/**
* #expectedException Exception
*/
public function test()
{
new Testme(1);
}
but what if it didn't do anything?
public function test()
{
new Testme(2);
?? ? ? ? ?
}
Scenarios
You have two possible scenarios for a function to do nothing:
Scenario 1: No return statement
Your function does nothing because you do not perform actions in it and you do not include the return keyword in it:
public function doNothing()
{
// Do nothing.
}
Scenario 2: With return statement
Your function does nothing because you do not perform actions in it and you do include the return keyword in it without expressing any return value:
public function doNothing()
{
// Do nothing.
return;
}
Other scenarios
I will leave out of the cases to treat the following scenarios:
Case in which you do not return anything but you perform significant actions that can be tested on other objects. In this case you must unit-test the resulting states of the modified objects.
Case in which you do nothing but return something, then you should unit-test the return value.
Exploring the documentation in the PHP manual
For the first case, the PHP manual documents that the evaluated expression of the function will be null. It says here: http://php.net/manual/en/functions.returning-values.php in a note:
If the return is omitted the value NULL will be returned.
For the second case, the PHP manual documents that the evaluated expression of the funcion will also be null. It says here: http://php.net/manual/en/function.return.php in a note:
If no parameter is supplied, then the parentheses must be omitted and NULL will be returned. [...]
Conclusion
It is therefore clearly documented that a function that "does nothing" necessarily evaluates to null.
How to test a function that does nothing
Just assert your expectations:
$this->assertNull( $sut->doNothing() );
This way you "exercise" your function, you run over it making the code-coverage complete all the lines, and you "expect" that "nothing happened" by testing the null value of its evaluation as an expression, as documented.
How to test a constructor that does nothing
Nevertheless to test a constructor... well... common sense: What's the purpose of a constructor? Create an object (instance) of a certain type (class), right?
So... I prefer to start the 100% of my unit tests by checking that the $sut has been created. This is the VERY first test I write when I'm writing the code of a new class. This is the test I write even before the class exists. At the end, this is what the constructor is for. Red bar. Then I create the class. Green bar.
Let's say I have an Email class that takes a string and will be only created if a valid email is passed and throws exception otherwise. this is very similar to your question. A constructor that just "allows the creation" or "denies it by exploding the system".
I usually would do something like this:
//-------------------------------------------------//
// Tests //
//-------------------------------------------------//
/** #dataProvider validEmailProvider **/
public function testCreationIsOfProperClass( string $email )
{
$sut = $this->getSut( $validEmail );
$this->assertInstanceOf( Email::class, $sut );
}
/** #dataProvider invalidEmailProvider **/
public function testCreationThrowsExceptionIfEmailIsInvalid( string $invalidEmail )
{
$this->expectException( EmailException::class );
$this->getSut( $invalidEmail );
}
//-------------------------------------------------//
// Data providers //
//-------------------------------------------------//
public function validEmailProvider() : array
{
return
[
[ 'alice#example.com' ],
[ 'bob.with-several+symbols#subdomain.another.subdomain.example.verylongTLD' ],
]
}
public function invalidEmailProvider() : array
{
return
[
[ 'missing_at_symbol' ],
[ 'charlie#cannotBeOnlyTld' ],
]
}
//-------------------------------------------------//
// Sut creators //
//-------------------------------------------------//
private function getSut( string $email ) : Email
{
return new Email( $email );
}
As I use PHP 7.0 and I put types everywhere, both entering the parameters and also in the return types, if the created object was not an Email, the getSut() function would fail first.
But even if I wrote it omitting the return type, the test tests what it is expected to happen: new Email( 'valid#example.com' ); is itself an expression that shoud evaluate to "something" of class Email::class.
How to test a constructor that does something
Code smell. The constructor probably should not do work. If any, just store parameters. If the constructor "does work" other than storing parameters consider lazy-processing on getters, or delegating that work in a factory or so.
How to test a constructor that "does nothing but store parameters"
Just like before + then get the data.
Test in your first test that the creation is an instance of something.
Then in another different test, exercise something like a getter that gets you what entered in the constructor even if the constructor did not anything (other than storing it).
Hope that this helps.
In PHPUnit 7.2+ you can also use TestCase::expectNotToPerformAssertions()
public function test()
{
// ...
$this->expectNotToPerformAssertions();
}
This has the same behaviour as the #doesNotPerformAssertions annotation.
2018+
Nowadays the best practice is annotation exactly for these cases:
/**
* #doesNotPerformAssertions
*/
public function testSomething()
{
$someService = new SomeObject();
$someService->shallNotFail();
}
Example pull-request
PHPUnit documentation (poor)
It's not possible. Add return statement and assert the result.
class Testme()
{
public function testMe ($a)
{
if ($a == 1)
{
throw new Exception ('YAY');
}
return true;
}
}
and then
$object = new Testme();
$this->assertTrue($object->testMe(2));
Note: The credits for this solution go to this related answer. The context may seem a little different, but the solution / workaround works the same way. Testing that an exception is not thrown is just the same as testing a method with no return value.
According to this issue thread, there is no built in solution for testing something like DoesNotThrowException in PHPUnit (yet).
So yes, one solution would be to return some dummy value from your method, like
public function testMe ($a)
{
if ($a == 1) { throw new Exception ('YAY'); }
return true;
}
and then assert it in your test. But if you don't want to change the code just for the test, you can work around it:
public function testExceptionIsNotThrown()
{
try {
new Testme(2);
}
catch(Exception $e) {
/* An exception was thrown unexpectedly, so fail the test */
$this->fail();
}
/* No exception was thrown, so just make a dummy assertion to pass the test */
$this->assertTrue(true);
}
It may seem hacky and not very intuitive, but if it's stupid but it works, it's not stupid.
This is an very interesting question, although lot of answers were written, none of them seems to properly answer the question, since you have asked using the class let me explain this way.
Please keep in mind that an instance method you have created in class should have only 2 intentions.
It can alter the state of a class ( change the class properties like private variables )
It returns the state of the class ( getters )
any thing other than this is meaningless unless it is a static method. for example
if you have class like this
class Foo {
private $prop = null;
public function fooMethod() {
$this->prop = "string";
}
public function getProp() {
return $this->prop;
}
}
the method fooMethod() does not return any thing, but it affects the state of $prop property in the class, you can test the method by
$this->assertNotNull( $instance->getProp() );
because you knew if this method is run then the prop $prop should be affected and state of that variable is changed.
Miscellanous Scenario: My method doesn't alter the state and also won't return any state variables.
Then the method is static. It should not be an instance method, and the static methods usually have return type, because they cant affect the state of the class and also can't return state variables. This constraints the static methods from storing a result somewhere (unless you store them globals, don't do that ), so it should definitely return some output. If you don't want to return output, then you could consider returning a boolean from static method.
public function testThrowingException()
{
$this->expectException(Exception::class);
$this->expectExceptionMessage('YAY');
(new Testme())->testMe(1);
}
public function testNotThrowingException()
{
$this->expectNotToPerformAssertions();
(new Testme())->testMe(2);
}
I stumled upon the same problem. To ensure "nothing" has happened it's enough to just call you the method in your unit test. If it fails the test will fail anyway.
If you just call your method without the #expectedException annotation like this
public function test()
{
new Testme(1);
}
you'll get an error
There was 1 error:
1) Testme::testMe
Exception: YAY

Cahining pattern

I have a class in php that works with the chainning method, but the problem is that I want to chain the methods in some order.
class Chain {
public function foo () {
return $this;
}
public function bar () {
return $this;
}
public function some () {
return $this;
}
}
So, if I use this class, then I can chain this methods in 9 different ways (all the possible combinations of 3 elements)
But what happen if I determine that the method some always must to be chained after foo or bar and not in other way?
$chain = new Chain();
$chain->foo->bar(); //works; i.e: the method some is optional
$chain->foo()->bar()->some(); //works
$chain->bar()->foo()->some(); //works
$chain->some()->bar()->foo(); //throws an exception
I think that I can do this setting boolean values, something like: when the method foo or bar are called, then I set the value to some var to true, and when the developer calls the some function, if that var is false, then throws an exception, otherwise is allowed to continue.
But I need something more elegant, such as pattern or a built-in solution.
There is another way to do it?
The very rough example I imagine will still have some lines of code in each method
<?php
class Chain {
private $_register = array();
public function foo () {
$this->register(__METHOD__);
return $this;
}
public function bar () {
$this->register(__METHOD__);
return $this;
}
public function some () {;
$this->verify('foo'); // foo() should be called before some();
$this->register(__METHOD__);
echo 'it\'s ok';
return $this;
}
public function verify($method) {
if(array_key_exists($method, $this->_register) && $this->_register[$method] == true) {
return true;
}
else {
throw new Exception('Some exception');
}
}
public function register($method) {
$method = str_replace(__CLASS__.'::', '', $method);
$this->_register[$method] = true;
}
}
What do we do here - we have a register() and verify() methods. (they can be helpers, but for the current purpose I added them in the class.
Each method should have before it's returning value a register to itself. Calling $this->register(__METHOD__) from foo() will add in the private array 'foo' => true.
The verify() method checks if foo exist as array key and if its value is true. If it is - the script will continue. Otherwise - throws exception.
In this case:
$chain = new Chain();
$chain->bar()->some()->foo(); //throws an exception
Fatal error: Uncaught exception 'Exception' with message 'Some
exception' in ...
$chain = new Chain();
$chain->foo()->some()->foo(); // ok
it's ok
The problem here is that we establish a "convention". You need to pass __METHOD__ to the register function so after it replace the classname it will add only the method name in the array. So later, in the function where you need to verify if one or more functions are called before this, you need to use the method name as string i.e. $this->verify('foo');
Ofcourse you can play different scenarios without stripping and testing with strpos() or adding () after the methodname for easier recognition if you are verifying a method or smth else.
But at least it will save you from making for each method, different variable to fill i.e.
function foo() {
$this->_foo = true;
return $this;
}
function bar() {
$this->_bar = true;
return $this;
}
Forcing the caller to stick to a certain order of calls just as an end to itself is hardly useful at all. Supposedly what you're really interested in is to make sure the state of the object is valid when you call some() and throw an exception if it's not. In that case, yes, you would check certain indicators of your object's state and throw an exception when this state does not fulfil the requirements that some() may be called. As a concrete example:
$api = new SomeAPI;
$api->setUserID($id);
$api->setSecretKey($secret);
$api->call('something');
Here call() would check that the user id and access key has been set, otherwise it can't do its job. Whether these calls are chained or not is irrelevant and just a syntactic detail.
Alternatively, you could return certain objects of other (sub) classes from your methods which physically make it impossible to call certain methods on them if certain conditions haven't been met:
public function bar() {
if ($this->foo) {
return new SubFoo($this->foo);
} else {
return new SubBar;
}
}
This may be overly complicated though.

Categories