Closed vlradstake closed 2 years ago
TestRequest::fake(
status: 200,
)->withToken('foobar')
->withData([
'title' => 'Build a package'
])->withFakeData([
'data' => 'faked'
])->send();
$responses = Concurrently::fake()->setRequests([
TestRequest::fake()->setPath(
path: '/todos/1',
)->as(
key: 'first'
),
TestRequest::fake()->setPath(
path: '/todos/2',
)->as(
key: 'second'
),
TestRequest::fake()->setPath(
path: '/todos/3',
)->as(
key: 'thirds'
),
])->run();
For Normal Request
TestRequest::fake( status: 200, )->withToken('foobar') ->withData([ 'title' => 'Build a package' ])->withFakeData([ 'data' => 'faked' ])->send();
For Concurrency
$responses = Concurrently::fake()->setRequests([ TestRequest::fake()->setPath( path: '/todos/1', )->as( key: 'first' ), TestRequest::fake()->setPath( path: '/todos/2', )->as( key: 'second' ), TestRequest::fake()->setPath( path: '/todos/3', )->as( key: 'thirds' ), ])->run();
This is 👌
The idea was that the only thing you need to swap is build()
to fake()
which accepts an optional status code for you to return, for bad path and alternative status code testing. Then you can also fake the response data coming back with withFakeData()
if you want/need to at all.
@JustSteveKing @AbdullahFaqeir So this example should work? Maybe i am doing something wrong but if i run this test TestRequest::build()->send()->json()
returns the real data and not the fake data.
class ExampleControllerTest extends TestCase
{
public function test_it_can_fake_data()
{
TestRequest::fake()
->withFakeData(
['data' => 'faked']
)->send();
$response = $this->get('/');
}
}
@vlradstake do you have a repo or gist for the request you are trying to send? I would need to see the actual Transporter request to know what to do - but feel free to strip out anything sensitive or business critical.
All you should need to do in theory is switch the build
method for a fake
method, and add an array in withFakeData
for the response body you want back
@JustSteveKing sorry took some time, had to check some things first. This is the code from the application, is this enough?
class CraftCmsRestRequest extends \JustSteveKing\Transporter\Request
{
public function __construct(HttpFactory $http)
{
$this->baseUrl = config('transporter.craft_cms.base_uri');
$this->baseUrl .= '/api';
parent::__construct($http);
}
protected function withRequest(PendingRequest $request): void
{
$request->contentType('application/json');
}
}
class ListRetour extends CraftCmsRestRequest
{
protected string $method = 'GET';
protected string $path = '/redirects';
protected function withRequest(PendingRequest $request): void
{
$this->withQuery(
[
'domain' => request()->getSchemeAndHttpHost(),
'siteHandle' => MultiSite::getConfig('craft.siteHandle'),
]
);
parent::withRequest($request);
}
}
class ResolvePageTest extends TestCase
{
public function test_it_can_resolve_data()
{
ListRetour::fake(status: 200)->withFakeData(
[
'test' => 'test'
]
)->send();
$data = $this->app->make(SyncRetourList::class)->execute();
}
}
class SyncRetourList
{
public function execute(): void
{
$list = ListRetour::build()->send()->json();
// i would expect the fake data here, but i get the real api data.
$cache = CacheHelper::getCacheStore('craft.redirects');
$cacheKey = CacheHelper::getCmsCacheKey('redirects');
$cache->forever($cacheKey, $list);
}
}
@vlradstake you issue seems to be here:
class SyncRetourList
{
public function execute(): void
{
$list = ListRetour::build()->send()->json(); // <--
}
}
Transporter is designed to swap build()
with fake()
to fake the request, so what this class is doing, isn't actually faking the request
@JustSteveKing ok, i understand. So how can i fake the data in the test? When i use the Laravel Htttp client i can add Http::fake
in the test to make this work.
Another way is to write something like this, but this feels wrong :p
class SyncRetourList
{
public function execute(): void
{
if(app()->environment('testing')) {
$list = ListRetour::fake()->send()->json();
} else {
$list = ListRetour::build()->send()->json();
}
}
}
This is something that you will have to figure out what works for you, in this situation I would approach things slightly differently. I would test that my transporter tests are working, and then this class I would just test that it doesn't throw any exception.
You have 2 bits of logic here, the request and the wrapping class. Do you need to test that the wrapping class calls the code it is supposed to? Or do you just test the request itself.
If this were my code I would:
class SyncRetourList
{
public function execute(): void
{
$response = ListRetour::build()->send();
if ($response->failed()) {
throw $response->toException();
}
}
}
As this class isn't actually returning anything you either want to send a request or want to throw a HTTP exception. You could try something like:
class SyncRetourList
{
public function execute(string $method = 'build', null|array $data = null): void
{
$request = ListRetour::$method();
if (! is_null($data) && $method === 'fake') {
$request->withFakeData($data);
}
$response = $request->send();
if ($response->failed()) {
throw $response->toException();
}
}
}
Which would allow you to:
(new SyncRetourList)->execute('fake')
@JustSteveKing Thanks for helping out! Found a way to fake the data in the tests:
class ResolvePageTest extends TestCase
{
public function test_it_can_resolve_data()
{
$this->app
->when(ListRetour::class)
->needs(HttpFactory::class)
->give(function () {
return (new HttpFactory())->fake(function ($request) {
return Http::response(['data' => 'here'], 200);
});
});
$data = $this->app->make(SyncRetourList::class)->execute();
}
}
That's really helpful to know! Thanks @vlradstake - I may add that to the readme for others 🙂
I'm trying to fake some data in my project tests. But
Http::fake()
doesn't seem to work, is there a why to fake the data?