How to mock internal calls with mockery
I try to mock a method of my service with Mockery lib. It works if I call that method from the test's context. But if I call it from another method (for example, it calls from another tested method) - it returns original data from implementation, but not from mock. What I'm doing wrong?
The example is below.
I added contract's because of my real implementation uses it. I don't think the problem is related to interfaces.
app/Contracts/TransactionsServiceContract.php
namespace AppContracts;
interface TransactionsServiceContract
{
public function getAllRequests(): array;
public function getRequests(array $necessaryFields): array;
}
app/Services/TransactionsService.php
namespace AppServices;
use AppContractsTransactionsServiceContract;
class TransactionsService implements TransactionsServiceContract
{
public function getAllRequests(): array
{
return [
'foo' => [
'metric' => 'foo',
],
'bar' => [
'metric' => 'bar',
],
'another' => [
'metric' => [
// Some fields
],
],
];
}
public function getRequests(array $necessaryFields): array
{
// dd($this->getAllRequests()); // -> for the test context it returns original value (above's one)
return collect($this->getAllRequests())->only($necessaryFields)
->map(function (array $metric) {
return $metric['formula'];
})
->toArray();
}
}
tests/Feature/TransactionsServiceTest.php
namespace TestsFeature;
use AppContractsTransactionsServiceContract;
use TestsTestCase;
class TransactionsServiceTest extends TestCase
{
/** @var TransactionsServiceContract */
private $_transactionsService;
public function setUp()
{
parent::setUp();
$requests = [
'test1' => [
'metric' => 'test 1',
],
'test2' => [
'metric' => 'test 2',
],
];
$this->_transactionsService = Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial();
$this->_transactionsService->shouldReceive('getAllRequests')->andReturn($requests);
}
public function testInternalCall()
{
$directCall = $this->_transactionsService->getAllRequests(); // returns array "requests" from the setUp method
dump($directCall);
$internalCall = $this->_transactionsService->getRequests(['test1']);
dd($internalCall); // if we call getAllRequests into getRequests, but not from test's context, we get original array from real implementation, but not test's mock
}
}
Versions of libs/frameworks:
- Laravel: v5.7.19
- PHPUnit: 7.5.1
- Mockery: 1.2.0
Thanks for attention. Happy new year! :)
laravel phpunit mockery
add a comment |
I try to mock a method of my service with Mockery lib. It works if I call that method from the test's context. But if I call it from another method (for example, it calls from another tested method) - it returns original data from implementation, but not from mock. What I'm doing wrong?
The example is below.
I added contract's because of my real implementation uses it. I don't think the problem is related to interfaces.
app/Contracts/TransactionsServiceContract.php
namespace AppContracts;
interface TransactionsServiceContract
{
public function getAllRequests(): array;
public function getRequests(array $necessaryFields): array;
}
app/Services/TransactionsService.php
namespace AppServices;
use AppContractsTransactionsServiceContract;
class TransactionsService implements TransactionsServiceContract
{
public function getAllRequests(): array
{
return [
'foo' => [
'metric' => 'foo',
],
'bar' => [
'metric' => 'bar',
],
'another' => [
'metric' => [
// Some fields
],
],
];
}
public function getRequests(array $necessaryFields): array
{
// dd($this->getAllRequests()); // -> for the test context it returns original value (above's one)
return collect($this->getAllRequests())->only($necessaryFields)
->map(function (array $metric) {
return $metric['formula'];
})
->toArray();
}
}
tests/Feature/TransactionsServiceTest.php
namespace TestsFeature;
use AppContractsTransactionsServiceContract;
use TestsTestCase;
class TransactionsServiceTest extends TestCase
{
/** @var TransactionsServiceContract */
private $_transactionsService;
public function setUp()
{
parent::setUp();
$requests = [
'test1' => [
'metric' => 'test 1',
],
'test2' => [
'metric' => 'test 2',
],
];
$this->_transactionsService = Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial();
$this->_transactionsService->shouldReceive('getAllRequests')->andReturn($requests);
}
public function testInternalCall()
{
$directCall = $this->_transactionsService->getAllRequests(); // returns array "requests" from the setUp method
dump($directCall);
$internalCall = $this->_transactionsService->getRequests(['test1']);
dd($internalCall); // if we call getAllRequests into getRequests, but not from test's context, we get original array from real implementation, but not test's mock
}
}
Versions of libs/frameworks:
- Laravel: v5.7.19
- PHPUnit: 7.5.1
- Mockery: 1.2.0
Thanks for attention. Happy new year! :)
laravel phpunit mockery
add a comment |
I try to mock a method of my service with Mockery lib. It works if I call that method from the test's context. But if I call it from another method (for example, it calls from another tested method) - it returns original data from implementation, but not from mock. What I'm doing wrong?
The example is below.
I added contract's because of my real implementation uses it. I don't think the problem is related to interfaces.
app/Contracts/TransactionsServiceContract.php
namespace AppContracts;
interface TransactionsServiceContract
{
public function getAllRequests(): array;
public function getRequests(array $necessaryFields): array;
}
app/Services/TransactionsService.php
namespace AppServices;
use AppContractsTransactionsServiceContract;
class TransactionsService implements TransactionsServiceContract
{
public function getAllRequests(): array
{
return [
'foo' => [
'metric' => 'foo',
],
'bar' => [
'metric' => 'bar',
],
'another' => [
'metric' => [
// Some fields
],
],
];
}
public function getRequests(array $necessaryFields): array
{
// dd($this->getAllRequests()); // -> for the test context it returns original value (above's one)
return collect($this->getAllRequests())->only($necessaryFields)
->map(function (array $metric) {
return $metric['formula'];
})
->toArray();
}
}
tests/Feature/TransactionsServiceTest.php
namespace TestsFeature;
use AppContractsTransactionsServiceContract;
use TestsTestCase;
class TransactionsServiceTest extends TestCase
{
/** @var TransactionsServiceContract */
private $_transactionsService;
public function setUp()
{
parent::setUp();
$requests = [
'test1' => [
'metric' => 'test 1',
],
'test2' => [
'metric' => 'test 2',
],
];
$this->_transactionsService = Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial();
$this->_transactionsService->shouldReceive('getAllRequests')->andReturn($requests);
}
public function testInternalCall()
{
$directCall = $this->_transactionsService->getAllRequests(); // returns array "requests" from the setUp method
dump($directCall);
$internalCall = $this->_transactionsService->getRequests(['test1']);
dd($internalCall); // if we call getAllRequests into getRequests, but not from test's context, we get original array from real implementation, but not test's mock
}
}
Versions of libs/frameworks:
- Laravel: v5.7.19
- PHPUnit: 7.5.1
- Mockery: 1.2.0
Thanks for attention. Happy new year! :)
laravel phpunit mockery
I try to mock a method of my service with Mockery lib. It works if I call that method from the test's context. But if I call it from another method (for example, it calls from another tested method) - it returns original data from implementation, but not from mock. What I'm doing wrong?
The example is below.
I added contract's because of my real implementation uses it. I don't think the problem is related to interfaces.
app/Contracts/TransactionsServiceContract.php
namespace AppContracts;
interface TransactionsServiceContract
{
public function getAllRequests(): array;
public function getRequests(array $necessaryFields): array;
}
app/Services/TransactionsService.php
namespace AppServices;
use AppContractsTransactionsServiceContract;
class TransactionsService implements TransactionsServiceContract
{
public function getAllRequests(): array
{
return [
'foo' => [
'metric' => 'foo',
],
'bar' => [
'metric' => 'bar',
],
'another' => [
'metric' => [
// Some fields
],
],
];
}
public function getRequests(array $necessaryFields): array
{
// dd($this->getAllRequests()); // -> for the test context it returns original value (above's one)
return collect($this->getAllRequests())->only($necessaryFields)
->map(function (array $metric) {
return $metric['formula'];
})
->toArray();
}
}
tests/Feature/TransactionsServiceTest.php
namespace TestsFeature;
use AppContractsTransactionsServiceContract;
use TestsTestCase;
class TransactionsServiceTest extends TestCase
{
/** @var TransactionsServiceContract */
private $_transactionsService;
public function setUp()
{
parent::setUp();
$requests = [
'test1' => [
'metric' => 'test 1',
],
'test2' => [
'metric' => 'test 2',
],
];
$this->_transactionsService = Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial();
$this->_transactionsService->shouldReceive('getAllRequests')->andReturn($requests);
}
public function testInternalCall()
{
$directCall = $this->_transactionsService->getAllRequests(); // returns array "requests" from the setUp method
dump($directCall);
$internalCall = $this->_transactionsService->getRequests(['test1']);
dd($internalCall); // if we call getAllRequests into getRequests, but not from test's context, we get original array from real implementation, but not test's mock
}
}
Versions of libs/frameworks:
- Laravel: v5.7.19
- PHPUnit: 7.5.1
- Mockery: 1.2.0
Thanks for attention. Happy new year! :)
laravel phpunit mockery
laravel phpunit mockery
asked Jan 2 at 10:16
Pavel SavushkinPavel Savushkin
1
1
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
When you call Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial(); in your setUp method, you're not really replacing the implementation existing in the app container. Laravel's container provides you with the bind method, to do that (the documentation for that). Besides you wouldn't replace an interface with a mock, as interfaces don't do anything per definition.
So in fact you would do something like:
app()->bind('AppTransactionsService', $mockedTransactionService);
Note this will only work if your code gets an instance of the TransactionService by injection or resolving, not by calling
new TransactionService.
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54004518%2fhow-to-mock-internal-calls-with-mockery%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
When you call Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial(); in your setUp method, you're not really replacing the implementation existing in the app container. Laravel's container provides you with the bind method, to do that (the documentation for that). Besides you wouldn't replace an interface with a mock, as interfaces don't do anything per definition.
So in fact you would do something like:
app()->bind('AppTransactionsService', $mockedTransactionService);
Note this will only work if your code gets an instance of the TransactionService by injection or resolving, not by calling
new TransactionService.
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
add a comment |
When you call Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial(); in your setUp method, you're not really replacing the implementation existing in the app container. Laravel's container provides you with the bind method, to do that (the documentation for that). Besides you wouldn't replace an interface with a mock, as interfaces don't do anything per definition.
So in fact you would do something like:
app()->bind('AppTransactionsService', $mockedTransactionService);
Note this will only work if your code gets an instance of the TransactionService by injection or resolving, not by calling
new TransactionService.
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
add a comment |
When you call Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial(); in your setUp method, you're not really replacing the implementation existing in the app container. Laravel's container provides you with the bind method, to do that (the documentation for that). Besides you wouldn't replace an interface with a mock, as interfaces don't do anything per definition.
So in fact you would do something like:
app()->bind('AppTransactionsService', $mockedTransactionService);
Note this will only work if your code gets an instance of the TransactionService by injection or resolving, not by calling
new TransactionService.
When you call Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial(); in your setUp method, you're not really replacing the implementation existing in the app container. Laravel's container provides you with the bind method, to do that (the documentation for that). Besides you wouldn't replace an interface with a mock, as interfaces don't do anything per definition.
So in fact you would do something like:
app()->bind('AppTransactionsService', $mockedTransactionService);
Note this will only work if your code gets an instance of the TransactionService by injection or resolving, not by calling
new TransactionService.
answered Jan 7 at 14:38
BorisuBorisu
520210
520210
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
add a comment |
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
thanks for your answer! In other words, I cannot mock methods of the class which will be returned from DI, right? So, I need to create an instance $mockedTransactionService (via new), mock methods and then bind it to my contract? Well, yes. It makes sense because the test file is created for testing exactly implementation. Thanks for your help!
– Pavel Savushkin
Jan 9 at 16:41
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54004518%2fhow-to-mock-internal-calls-with-mockery%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown