@bwrigley You are now mocking the eloquent model, while I would suggest mocking the payment class itself. And I think you would even be better of with a Fake instead of a mock.
Create an interface
One option, is to create a PaymentGatewayInterface. This interface can be implemented by a StripePaymentGateway and a FakePaymentGateway.
// PaymentGateWayInterface.php class:
interface PaymentGatewayInterface
{
//
}
// StripePaymentGateway.php class:
class StripePaymentGateway implements PaymentGatewayInterface
{
public function pay()
{
// logic for payment
}
// ...
}
// FakePaymentGateway.php class:
class FakePaymentGateway implements PaymentGatewayInterface
{
public function pay()
{
return 'fake method called';
}
// ...
}
Define default concrete implementation
In the service container you bind the StripePaymentGateway as the concrete implementation of the PaymentGatewayInterface.
// AppServiceProvider
public function register()
{
$this->app->bind(PaymentGatewayInterface::class, StripePaymentGateway::class);
}
Inject the interface
So, when your model needs an instance of a PaymentGatewayInterface, it will be resolved (via dependency injection) to your StripePaymentGateway concrete class.
// Eloquent model
public function testMethod(PaymentGatewayInterface $paymentGateway)
{
$paymentGateway->pay();
}
Swap interface to fake concrete implementation
Now, in your tests, you can swap the binding in the service container to use the FakePaymentGateway whenever an instance of the PaymentGatewayInterface is requested.
// Test class
// ...
$this->app->instance(PaymentGatewayInterface::class, FakePaymentGateway::class);
// your post request here
Also, Adam Wathan has a great course on TDD with Laravel, in which he discusses (amongst a plethora of other things) a lot of Stripe related testing. I can highly recommend https://testdrivenlaravel.com