# |
May 14th 2021, 16:30 |
matthttam |
All I know is that I want the code in the controller action: ```$this->loadModel('Freshservice.Locations', 'Endpoint'); $locations = $this->Locations->find('all')->toArray(); $this->set(compact('locations'));``` when ran by the test to work. So in my mind, I need the loadModel to not fail. And the $this->Locations->find('all')->toArray(); to create a predefined array of information. Would you recommend a mock or a stub to |
# |
May 14th 2021, 16:29 |
ndm |
As mentioned, it doesn't make much of a difference in your specific case, given how simple the code is. |
# |
May 14th 2021, 16:25 |
slackebot |
verifying behavior. |
# |
May 14th 2021, 16:25 |
ndm |
@matthttam It depends on where/how you use the mock. Generally a mock is ment to test whether it is interacted with in the way you expect it to, whether this is required/helpful/etc, depends. A stub will not cause a failure when the configured methods are not being invoked, or when they're invoked the wrong way. That information might be helpful to figure why things go wrong, even if your situation doesn't technically require |
# |
May 14th 2021, 15:52 |
matthttam |
Again, very new to this and I feel this is quite advanced. So my perceptions of how these are used could be very wrong. I've just been reading the PHPUnit docs |
# |
May 14th 2021, 15:51 |
matthttam |
I'll check that. But, it seems to me that Mock is meant to test the class itself sort of. But I am not testing that Locations->find() returns a query... I'm just trying to test that getting 'assets/test' loads properly. So, does it not make sense to just stub the "Endpoint" model to make that variable populate properly in the controller during the test? |
# |
May 14th 2021, 15:46 |
ndm |
Making your code shorter isn't a good reason, whether to use a stub or a mock should depend on what is appropriate/required from a purely technical point of view. `$this` in a closure will always refer to the outer scope. Again, check your error logs for information on what exactly is causing that 500 error. |
# |
May 14th 2021, 15:40 |
matthttam |
And, I can't use the EventManager::instance() for some reason... the code inside just throws a 500 error. I'm guessing because "this" isn't the test class anymore but rather the eventmanager class and I don't know how to fix this honestly |
# |
May 14th 2021, 15:39 |
slackebot |
presumably queryStub would have methods for returning an array The problem is I'm still stuck on: ```InvalidArgumentException: Unknown repository type "Endpoint". Make sure you register a type before trying to use it.``` |
# |
May 14th 2021, 15:39 |
matthttam |
I'm leaning to making a stub of each element to make this work and it may be because I don't completely understand _how_ to make a simple test run when I'm using this plugin.... I guess the "why" is so that _if_ I can make the code: ```$locator = \Cake\Datasource\FactoryLocator::get('Endpoint'); $locator->set('Freshservice.Locations', $locationsStub);``` work then I can just do a ->method('find')->willReturn($queryStub) Then |
# |
May 14th 2021, 15:36 |
ndm |
@matthttam The answer probably lies in the "_why_" you'd want to do that. It doesn't make much of a difference, stubs are just more lenient mocks, as they are ment to not define expectations. |
# |
May 14th 2021, 15:20 |
kevin.pfeifer |
@greenmanspirit hmm, seems strange. Got anything particular in your logs? It should work the same way from B => C if it already works from C => B |
# |
May 14th 2021, 15:17 |
greenmanspirit |
@kevin.pfeifer I have $this->belongsToMany('B'); in C and $this->belongsToMany('C'); in B |
# |
May 14th 2021, 15:16 |
matthttam |
@ndm What if.... What if I stubbed the LocationsEndpoint::class. Then mocked the query that is returned? |
# |
May 14th 2021, 15:13 |
kevin.pfeifer |
@greenmanspirit and you are sure you configured the HABTM Connection in your Table correctly on the B Model side? |
# |
May 14th 2021, 15:12 |
greenmanspirit |
@kevin.pfeifer Yes, that works just fine. |
# |
May 14th 2021, 15:10 |
slackebot |
building custom locators (if you can't use DI yet), then you could wrap things in custom services that have a cleaner, easier to mock API. As far as the error is concerned, check your error logs for more details (`/logs/`), 500 indicates that an exception was thrown. |
# |
May 14th 2021, 15:10 |
slackebot |
->getMockBuilder(\Muffin\Webservice\Datasource\Query::class) ->onlyMethods(['toArray']) ->getMock(); $queryMock ->expects($this->once()) ->method('toArray') ->willReturn([ 'some test data' ]); $locationsMock ->expects($this->once()) ->method('find') ->willReturn($queryMock);``` With that amount of mocking required, especially mocking 3rd party code, you may want to consider learning about |
# |
May 14th 2021, 15:10 |
ndm |
@matthttam Yes, expectations define what you expect with your mocks to happen, for example `find` being invoked and returning an object that you've defined, one that provides a `toArray()` method that returns your test data. That's PhpUnit basics, so I'd highly recommended that you make yourself familiar with it first: https://phpunit.readthedocs.io/en/9.5/test-doubles.html Quick and dirty example: ```$queryMock = $this |
# |
May 14th 2021, 15:08 |
kevin.pfeifer |
but when you delete an entry from model C does it remove the connection data between C and B for that? |
# |
May 14th 2021, 14:59 |
greenmanspirit |
delete when B is deleted. Any help will be appreciated. |
# |
May 14th 2021, 14:59 |
greenmanspirit |
hello, I am using CakePHP 4. I have three models (A, B, C). A hasMany B with saveStrategy = replace, B HABTM C. I am managing B's records using this method https://codethepixel.com/cakephp/cakephp-dynamic-input-and-saveassociated adjusted for CakePHP 4. The B records add and remove just fine but I cannot get entries in the join table for B and C to |
# |
May 14th 2021, 14:50 |
slackebot |
$this->assertResponseOk(); }``` |
# |
May 14th 2021, 14:50 |
slackebot |
$locationsMock = $this ->getMockBuilder(\Freshservice\Model\Endpoint\LocationsEndpoint::class) ->onlyMethods(['find', 'toArray']) ->getMock(); $locator = \Cake\Datasource\FactoryLocator::get('Endpoint'); $locator->set('Freshservice.Locations', $locationsMock); }); $this->login(); $this->get('assets/test'); |
# |
May 14th 2021, 14:50 |
matthttam |
``` public function testTest(): void { //$this->modelFactory('Endpoint', ['Muffin\Webservice\Model\EndpointRegistry', 'factory']); //$locations = $this->getMockForAbstractClass( // 'Freshservice\Webservice\LocationsWebservice', // array(), 'Locations', false // ); \Cake\Event\EventManager::instance()->on('Controller.initialize', function () { |
# |
May 14th 2021, 14:50 |
matthttam |
```Time: 2 seconds, Memory: 16.00 MB There was 1 failure: 1) App\Test\TestCase\Controller\AssetsControllerTest::testTest Failed asserting that 500 is between 200 and 204.``` |
# |
May 14th 2021, 14:50 |
slackebot |
further than I've gotten in my days of playing with this problem |
# |
May 14th 2021, 14:50 |
matthttam |
@ndm... so it is failing less hard now I think. I'm trying to understand what adding expectations would look like. Or what that does exactly... In my head, I expect: ```$locations = $this->Locations->find('all')->toArray();``` to return an array of data... Does this mean I need to add an expect to it where the method "find" returns an a resource or something? I'm just so confused.... TY for your help though so far this is |
# |
May 14th 2021, 14:45 |
matthttam |
Yea, no sandbox I don't think... that would be nice |
# |
May 14th 2021, 14:44 |
ndm |
Also check whether your api has a sandbox |
# |
May 14th 2021, 14:43 |
matthttam |
The API is quite extensive and subject to change. it would be way to difficult to simulate the whole thing honestly. I just want to mock the endpoints/webservices I'm using so that the controller can be tested. https://api.freshservice.com/v2/ |
# |
May 14th 2021, 14:42 |
ndm |
Alternatively consider using some kind of dummy server for your test environment that simulates the API. |
# |
May 14th 2021, 14:42 |
ndm |
Yes. |
# |
May 14th 2021, 14:40 |
matthttam |
where do I put this? in the test itself? |
# |
May 14th 2021, 14:35 |
slackebot |
->onlyMethods(['the', 'methods', 'to', 'mock']) ->getMock(); // ... add expectations to mock $locator = \Cake\Datasource\FactoryLocator::get('Endpoint'); $locator->set('Freshservice.Locations', $locationsMock); });``` |
# |
May 14th 2021, 14:35 |
ndm |
I'm not familiar with that plugin, but the endpoint locator certainly seems to hold endpoint instances, so if you want to mock what `loadModel()` returns, then you'd probably want to mock `Freshservice\Model\Endpoint\LocationsEndpoint`. ```\Cake\Event\EventManager::instance()->on('Controller.initialize', function () { $locationsMock = $this ->getMockBuilder(\Freshservice\Model\Endpoint\LocationsEndpoint::class) |
# |
May 14th 2021, 14:29 |
matthttam |
But test doesn't know what to do with it |
# |
May 14th 2021, 14:28 |
matthttam |
The app itself works of course. It does the API call for realz and is currently just dumping a debug of $locations... |
# |
May 14th 2021, 14:28 |
matthttam |
Well... branch 3.0.0-RC3 though https://github.com/UseMuffin/Webservice/blob/3.0.0-RC3/src/Model/Endpoint.php |
# |
May 14th 2021, 14:27 |
matthttam |
I don't know enough of cakephp to do what you just asked honestly. I'm still trying to learn this beast of a framework. An endpoint extends Muffin\Webservice\Model\Endpoint https://github.com/UseMuffin/Webservice/blob/master/src/Model/Endpoint.php |
# |
May 14th 2021, 14:25 |
ndm |
Also a webservice isn't an endpoint, or is it? |