I have the following code:
public function addSomething($paramDto) {
try {
$this->privateMethod($param);
} catch(\Exception $e) {
return ['error' => true, 'messages' => [$e->getMessage()]];
}
return ['error' => false, 'messages' => 'success'];
}
private function privateMethod($param) {
if(!$param) {
throw new \Exception('errorMessage');
}
}
I'm trying to test the addSomething method, what the catch block returns, I don't want to test the private method.
public function testAddSomethingThrowError($paramDto) {
$param = \Mockery::mock('MyEntity');
$method = new \ReflectionMethod(
'MyService', 'privateMethod'
);
$method->setAccessible(TRUE);
$this->expectException(\Exception::class);
$this->getMyService()
->shouldReceive($method->invoke($param)
->withAnyArgs()
->andThrow(\Exception::class);
$this->getMyService()->addSomething($paramDto);
}
The thing is that if i run the test, it coverages the private method in the if statement and returns the exception, but the catch method in my addSomething method is not covered, actually it does not cover the addSomething method at all.
I am using the sebastian bergmann phpunit framework.
What am I doing wrong?
The correct answer should be Jakub Matczak's answer:
"You want to "assert if the public method is returning the message that it is indeed returning". There's no sense in doing that. Consider your tested class as a blackbox without possibility to check its source. Then make tests according to how to want it to work using its public interface. "
Related
I am new to Laravel and have an Issue regarding the Handler.php File.
I am trying to create a class that takes an exceptions and transforms it into a JSON Response.
Sadly though, upon calling the constructor a series of Errors are thrown:
(ErrorErrorErrorErrorErrorErrorErrorErrorErrorErrorErrorSymfony\Component\ErrorHandler\Error\FatalError)
My code:
render() in Handler.php:
public function render($request, Throwable $exception)
{
$errorResource = new ErrorResource($exception);
return $errorResource->getJsonResponse();
}
class ErrorResource in ErrorResource.php:
<?php
namespace Transformers;
use Throwable;
class ErrorResource
{
private $exception;
private $defaultCodes = [TypeError::class => 400];
private $defaultMessages = [TypeError::class => 'Untgültige URL Parameter'];
function __construct(Throwable $exception)
{
$this->exception = $exception;
}
public function getJsonResponse($exception)
{
$codeToThrow = 500;
$messageToThrow = "Internal Server Error";
$type = get_class($this->exception);
if (empty($exception->getCode())) {
$codeToThrow = $this->defaultCodes[$type];
} else {
$codeToThrow = $exception->getCode();
}
if (empty($exception->getMessage())) {
$messageToThrow = $this->defaultMessages[$type];
} else {
$messageToThrow = $exception->getMessage();
}
return response()->json(array(
'Type' => $type,
'Message' => $messageToThrow
), $codeToThrow);
}
}
I have also tried to move the method getJsonResponse() to the Handler.php file and call it from there, but without any luck.
I am really confused as to why I am not allowed to do certain things with the $exception variable (I have also tried to create a clone of this object - but the same error occures)
I hope you can help me resolving this issue,
Greetins,
Franz
The issue is, that PHP is call by value. That is why it is implicitely trying to clone an unclonable object -> Error. To resolve this issue one can use wrapper objects, but I decided to simply use call by reference (https://www.javatpoint.com/php-call-by-reference)
i have code.
try {
$this->entityManager->beginTransaction();
$this->repo->remove($something);
$this->repoTwo->delete($something);
$this->entityManager->commit();
} catch (Exception $e) {
$this->entityManager->rollback();
throw new Exception($e->getMessage(), 0, $e);
}
And now, i want to test, if there is still record in database, after exception, how i can do that, if test wont work after exception is expected?
$this->expectException(Exception::class);
$this->expectExceptionMessage('xxxx');
app(Command::class)->handle();
$this->seeInDatabase($table, [
'id' => $media->id(),
]);
How i can do that? Thanks.
Normally you might create two tests. One that tests an exception was thrown and one that depends on the first test and tests the record still exists, but in this case the database would be reset before each test, including test dependencies so it won't work as you might expect.
But you can still do two tests and have one depend on the other, however you need to re-run the same code in both test (because the database would be reset in between the tests). The "depends" in this case is merely documenting that one test is associated with the other.
public function testOne()
{
$this->expectException(Exception::class);
$this->expectExceptionMessage('xxxx');
app(Command::class)->handle();
}
/**
* #depends testOne
*/
public function testTwo($arg)
{
app(Command::class)->handle();
$this->seeInDatabase($table, [
'id' => $media->id(),
]);
}
If you really want to end-to-end test it, and do the assertions in the same test, then you can use a try ... catch block and test it procedurally.
public function testException()
{
try {
app(Command::class)->handle();
} catch (\Exception $e) {
// Make sure you catch the specific exception that you expect to be
// thrown, (e.g. the exception you would normally specify in the
// expectException method: $this->expectException(Exception::class);
// Assert the exception message.
$this->assertEquals('xxxx', $e->getMessage());
// Assert database still contains record.
$this->seeInDatabase($table, [
'id' => $media->id(),
]);
return;
}
// If the expected exception above was not caught then fail the test.
$this->fail('optional failure message');
}
So I am messing around with symfony router component and I created a small wrapper.
One thing that came up was how do I get a request to throw a 500 in unit tests? The method in question is:
public function processRoutes(Request $request) {
try {
$request->attributes->add($this->_matcher->match($request->getPathInfo()));
return call_user_func_array($request->attributes->get('callback'), array($request));
} catch (ResourceNotFoundException $e) {
return new RedirectResponse('/404', 302);
} catch (Exception $e) {
return new RedirectResponse('/500', 302);
}
}
And the test in question is:
public function testFiveHundred() {
$router = new Router();
$router->get('/foo/{bar}', 'foo', function($request){
return 'hello ' . $request->attributes->get('bar');
});
$response = $router->processRoutes(Request::create('/foo/bar', 'GET'));
$this->assertEquals(500, $response->getStatusCode());
}
Right now the test will fail because we are defined and the status code will be 200. Is there something special I can do to the Request object I create, to make it throw a 500?
I think you got several options here you can play with:
Decide that a specific path will always throw an exception.
This will force you to make some changes in your code.
public function processRoutes(Request $request) {
...
if ($request->getRequestUri() == '/path/that/throws/exception') {
throw Exception('Forced to throw exception by URL');
}
...
}
public function testFiveHundred() {
...
$response = $router->processRoutes(Request::create('/path/that/throws/exception', 'GET'));
...
}
Make a DummyRequest object that will extends your original Request class and make sure this object will raise an Exception (for example - you know for sure that you use the getPathInfo(), so you can use this).
class DummyRequest extends Request {
public function getPathInfo() {
throw new Exception('This dummy request object should only throw an exception so we can test our routes for problems');
}
}
public function testFiveHundred() {
...
$dummyRequest = new DummyRequest();
$response = $router->processRoutes($dummyRequest);
...
}
Since the function getRequestUri of our $dummyRequest throws an exception, your call to $router->processRoutes will have our dummy to throw that exception.
This is a general idea, you would probably need to play a bit with the namespaces and the functions there (I didn't test it, however this should work).
I am facing a PHPUnit issue in a Symfony2 context. I am testing the following method :
public function updatePassword(LdapUserInterface $user)
{
$data = array();
Attribute::setPassword($data, $user->getPassword(), Attribute::PASSWORD_UNICODEPWD);
try {
$this->ldap->bind();
$this->ldap->update($user->getDn(), $data);
return true;
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
throw new ConnectorException($this, 'Connector cannot connect to directory.');
} finally {
$this->ldap->disconnect();
}
return false;
}
I used the finally instruction PHP >5.5. My unitary test is ($this->logger references a stub defined in the setUp method):
/**
* #expectedException UserBundle\Connectors\Exceptions\ConnectorException
*/
public function testUpdatePasswordException()
{
$ldap = $this->getMockBuilder(Ldap::class)
->disableOriginalConstructor()
->setMethods(array('bind', 'disconnect', 'update'))
->getMock();
$ldap->method('update')->will($this->throwException(new LdapException($ldap, 'Fake Exception')));
$user = $this->getMockBuilder(User::class)
->setMethods(array('getDn', 'getPassword'))
->getMock();
$user->expects($this->once())->method('getPassword')->willReturn('#!12345mD');
$user->expects($this->once())->method('getDn')->willReturn('cn=John Doe,ou=people,dc=athome.com,dc=com');
$connector = new LdapConnector($this->logger, $ldap);
$connector->updatePassword($user);
}
The UT did not trigger any exception and failed. Apparently, the problem comes from the finally instruction. Normally, the disconnect method is called once and that's why I added it into the stub. But, when I removed it, the test passes.
While debugging, all instructions are called (try, catch, finally and then trigger of exception). I don't understand the behaviour of these, is it a php problem ? Seems not, so I wonder if there is not a problem with my mock or phpunit.
Any idea ?
I'm new to PHPUnit and Selenium, and I want to test a 'remove' button by confirming that an element with a given ID exists before the button is clicked, but no longer exists after the button is clicked.
If I use something like this to check that the element has been deleted:
$this->assertFalse($this->byId('idRemoved'));
Then I get a test failure in byId() because it can't find idRemoved (which is true, because it's not there.)
How can I test for the lack of an element, so the test fails if idRemoved is found?
This is what I ended up using, thanks to Karna's suggestion. I'm posting it as another answer as I am using PHP, so for the benefit of anyone else using PHPUnit and Selenium, here is a similar method to Karna's, but for PHPUnit:
try {
$this->byId('idRemoved');
$this->fail('The element was not deleted.');
} catch (PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) {
$this->assertEquals(PHPUnit_Extensions_Selenium2TestCase_WebDriverException::NoSuchElement, $e->getCode());
}
The code was taken from line 1070 in the PHPUnit Selenium test code, which I found after Karna pointed me in the right direction.
For those arriving late at the party: a better solution would be to create your own expected condition class and extend the Facebook\WebDriver\WebDriverExpectedCondition to write your own method:
public function elementNotPresent(WebDriverBy $by)
{
return new static(
function (WebDriver $driver) use ($by) {
try {
$driver->findElement($by);
return false;
} catch (Exception $e) {
return true;
}
}
);
}
Update: The above is intended for Facebook's Selenium WebDriver bindings for PHP
Java equivalent will be
public boolean isElementExists(By by) {
boolean isExists = true;
try {
driver.findElement(by);
} catch (NoSuchElementException e) {
isExists = false;
}
return isExists;
}
You can assert that a specific exception gets thrown if you'd like:
/**
* #expectedException MyException
* #expectedExceptionMessage Some Message
*/
public function testExceptionHasRightMessage()
{
//yourCodeThatThrows new MyException('Some Message')
}