-1

I have a laravel project and I got a problem with using PhpUnit test use Mockery. This is the fist time I use Mockery.

Below, I have some pseudo code:

class Mail
{
   public static function send($pin){ 
     // Perform send mail
     
     // This is fake current excetion
     throw new exception('Send mail error');
   }
}

class CompanyService
{
  
   public function providePin($pin)
   {
      try {
          // send mail but got exception
          Mail::send($pin);
          return true;
       }catch(\Exception $e) {
          // Write error to log file
          return false;
       }
   }

   
}

I have a test class below and I tried to bypass the exception in Mail::send($pin) but It's not working.

// I have a test class
class CompanyTest
{
   public function testProvidePin()
   {
      $mock = Mockery::mock(CompanyService::class)->makePartial();
      $res = $mock->shouldReceive('providePin')->with(300386)->times(1)->andReturn(true);
      // But everytime I got `false` at this
      $this->assertTrue($res);
   }
}

So, How can I bypass the exception in Mail::send($pin) ?

Thank for your help. 🙇🙇🙇🙇

4
  • So "providePin" doesn't throw the exception and stop the test, but it returns false which makes the test fail, am I correct ? Commented May 20, 2024 at 14:30
  • @Mohammadsiabbou Because Mail::send($pin) throw an exception, then providePin() will return false. Commented May 21, 2024 at 1:00
  • 1
    I think you should use DI here instead, did you look into that ? Commented May 21, 2024 at 9:05
  • 1
    Share your real code not an example please, else it is super difficult to help on your exact case as Laravel may have something in place but you are not sharing your real case Commented May 21, 2024 at 9:36

2 Answers 2

1

If your test resembles the pseudocode, then you're missing the call:

Mail::send($pin);

before:

$this->assertTrue($res);

in your test.

Try to put dd($res); before $this->assertTrue($res); to see what I mean:

You're trying to assert that "Mockery Expectation" object is boolean true, which fails the test. With Mockery, you're just setting up the test expectations: what should happen when certain method gets called. But you still need to make sure that that method does get called.

Sign up to request clarification or add additional context in comments.

Comments

1

I will leave this as an answer instead of a comment because if it is your case, it will already solve your issue:

So, if your Mail class is a Facade in your real code, then you don't even need Mockery at all (no need to initialize it). There is a dedicated section in the Laravel's documentation about testing Facades.

If it is a Facade, your test code should be like this:

class CompanyTest
{
    public function testProvidePin()
    {
        CompanyService::shouldReceive('providePin')
            ->with(300386)->times(1)->andReturn(true);

        // Execute your real code

        // Assert something
    }
}

On my experience, you should never create pure static classes, because you cannot mock them, so either use a normal class that you have to initialize, or just declare them as a Facade (have in mind that they are a Singleton), so it is super easy to mock or spy them.

1 Comment

This is not a pure (static) class, but nevertheless the wording, I'm absolutely with you that the issue is complaining about calling a static method (global function) and then complaining it works properly only wanting to have it fail in test. You can't have the cake and eat it, too. +1 for the answer, esp. in Laravel context, great insights! One outcome could perhaps be to make that class a facade. I'm sure Laravell docs have that covered (but better use DI for (own) interfaces (pure abstract classes they are called sometimes)).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.