I am using version v1.4.2.18. The library can be found here: https://github.com/Youshido/GraphQL
I am trying to accomplish the following:
query {
articleSummary(id:1) {
title,
body,
article {
id
}
}
}
I have an ArticleSummaryField.php:
class ArticleSummaryField extends AbstractField
{
public function build(FieldConfig $config)
{
$config->addArgument('id', new NonNullType(new StringType()));
}
public function getType()
{
return new ArticleSummaryType();
}
public function resolve($value, array $args, ResolveInfo $info)
{
return [
'title' => 'test title',
'body' => 'test body',
'article' => $args['id']
];
}
}
Then the ArticleSummaryType.php:
class ArticleSummaryType extends AbstractObjectType
{
public function build($config)
{
$config
->addField('title', new StringType());
->addField('body', new StringType());
->addField('article', new ArticleField());
}
}
Then the ArticleField.php has the getType method return the ArticleType which has the id field.
However what i am getting is an error:
Fatal error: Uncaught Error: Call to undefined method ArticleField::getNullableType() in .../vendor/youshido/graphql/src/Execution/Processor.php on line 135
What seems to be happening is that when $targetField->getType() on line 135 in src/Execution/Processor.php is called its returning the ArticleField class, not the ArticleType class.
I would expect that to return the class as declared in the 'getType' method on the ArticleField class.
Am i going about this wrong for nesting fields? Or is there a bug in the library?
To accomplish this you only pass the Field class as the first argument.
class ArticleSummaryType extends AbstractObjectType
{
public function build($config)
{
$config
->addField('title', new StringType());
->addField('body', new StringType());
->addField(new ArticleField());
}
}
Then in the field class you can override getName to set the name for the field as needed or it will use the class name as the field name.
Related
I want to use a UUID as a part of a URL:
https://example.com/books/fiction/don-quixote-37d8d0a6-692a-11ed-9022-0242ac120002
Where in my controller should I generate this UUD?
class BookController extends Controller
{
public function store(BookStoreRequest $request)
{
$this->authorize('create', Book::class);
$validated = $request->validated();
$validated['identifier'] = (string) Str::uuid();
$book = Book::create($validated);
}
}
Above results in the error:
SQLSTATE Field 'identifier' doesn't have a default value
This assume that the value for identifier wasn't passed correctly?
Solution is to add a boot function to the model:
public static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->identifier = Str::uuid();
});
}
I'm casting class Process to ProcessDTO. The ProcessDTO object have a property named ProcessSteps that does not exist in Process. I want the ProcessSteps-property to be casted to ProcessStepsDto. I'm using a global configuration for AutoMapper.
I have tried using
CreateMap<Process, ProcessDto>()
.ForMember(dest=>dest.Steps, opt => opt.MapFrom(s => Mapper.Map<ProcessStepDto>(s)));
But this is wrong..
public class Process
{
}
public class ProcessDto
{
//This property does not exists in source object and get's created on get. I want this to be cast to "ProcessStepDto[]"
public ProcessStep[] Steps
{
get
{
ProcessStepRepository repository = new ProcessStepRepository();
return repository.Select(x => x.ProcessId == this.Id && x.Active).OrderBy(x=>x.Position).ToArray();
}
}
}
public class ProcessStep
{
...
}
public class ProcessStepDto
{
...
}
UPDATE
After i use AutoMapper to mapp my object Process to ProcessDto i also want the property of Stepsto be mapped to ProcessStepsDto. Currently it stays as ProcessStep.
If you want to return ProcessDto with ProcessStepDto[], the ProcessDto should define the property with type ProcessStepDto[] instead of ProcessStep[].
public class ProcessDto
{
public ProcessStepDto[] Steps
{
get
{
ProcessStepRepository repository = new ProcessStepRepository();
return repository.Select(x => x.ProcessId == this.Id && x.Active).Select(s => new ProcessStepDto { PropertyInProcessStepDto = s.PropertyInProcessStep }).OrderBy(x=>x.Position).ToArray();
}
}
}
I just started with learning how to test within Laravel. I came across some problems though..
I'm testing my controller and want to check if a View has a variable assigned.
My controller code:
class PagesController extends \BaseController {
protected $post;
public function __construct(Post $post) {
$this->post = $post;
}
public function index() {
$posts = $this->post->all();
return View::make('hello', ['posts' => $posts]);
}
}
And my view contains a foreach loop to display all posts:
#foreach ($posts as $post)
{{post->id}}
#endforeach
Last but not least my test file:
class PostControllerTest extends TestCase {
public function __construct()
{
// We have no interest in testing Eloquent
$this->mock = Mockery::mock('Eloquent', 'Post');
}
public function tearDown()
{
Mockery::close();
}
public function testIndex() {
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->app->instance('Post', $this->mock);
$this->call('GET', '/');
$this->assertViewHas('posts');
}
}
Now comes the problem, when I run "phpunit" the following error appears:
ErrorException: Invalid argument supplied for foreach()
Any ideas why phpunit returns this error?
Your problem is here:
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->post->all() (which is what you're mocking) should return an array, and that's what your view expects. You're returning a string.
$this->mock->shouldReceive('all')->once()->andReturn(array('foo'));
should take care of the error you have, though you'll then get an error of the "Getting property of non-object" type.
You could do this:
$mockPost = new stdClass();
$mockPost->id = 1;
$this->mock->shouldReceive('all')->once()->andReturn(array($mockpost));
You should mock the view as well:
public function testIndex() {
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->app->instance('Post', $this->mock);
View::shouldReceive('make')->with('hello', array('posts', 'foo'))->once();
$this->call('GET', '/');
}
I'm going through the zend tutorials and I am testing a class with a mock object with phpunit. When I pass a mock created from Zend\Db\TableGateway to my class, who's constructor expects a Zend\Db\TableGateway, I get an type error:
"...Argument 1 passed to Album\Model\AlbumTable::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, instance of Mock_TableGateway_65b55cb0 given..."
Is this supposed happen? Are phpunit mock objects supposed to be able to "fool" the class?
Here is the real class:
class AlbumTable {
protected $tableGateway;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
}
public function fetchAll() {
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function getAlbum($id){
$id = (int) $id;
$rowset = $this->tableGateway->select(array('id' => $id));
$row = $rowset->current();
if(!$row) {
throw new \Exception("Couldn't find row: $id");
}
return $row;
}
public function saveAlbum(Album $album) {
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
$id = (int)$album->id;
if ($id == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getAlbum($id)) {
$this->tableGateway->update($data, array('id' => $id));
} else {
throw new \Exception('Form id does not exist');
}
}
}
public function deleteAlbum($id) {
$this->tableGateway->delete(array('id' => $id));
}
}
and the test:
class AlbumTableTest extends PHPUnit_Framework_TestCase {
public function testFetchAllReturnsAllAlbums() {
$resultSet = new ResultSet();
$mockTableGateway = $this->getMock('Zend\Db\TableGateway',
array('select'), array(), '', false);
$mockTableGateway->expects($this->once())
->method('select')
->with()
->will($this->returnValue($resultSet));
$albumTable = new AlbumTable($mockTableGateway);
$this->assertSame($resultSet, $albumTable->fechAll());
}
}
and the error:
Time: 102 ms, Memory: 5.00Mb
There was 1 error:
1) AlbumTest\Model\AlbumTableTest::testFetchAllReturnsAllAlbums
Argument 1 passed to Album\Model\AlbumTable::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, instance of Mock_TableGateway_65b55cb0 given, called in C:\Users\MEEE\Google Drive\code\iis\www\CommunicationApp\module\Album\test\AlbumTest\Model\AlbumTableTest.php on line 20 and defined
C:\Users\MEEE\Google Drive\code\iis\www\CommunicationApp\module\Album\src\Album\Model\AlbumTable.php:9
C:\Users\MEEE\Google Drive\code\iis\www\CommunicationApp\module\Album\test\AlbumTest\Model\AlbumTableTest.php:20
FAILURES!
Tests: 4, Assertions: 9, Errors: 1.
You are not mocking the correct class. You are creating a mock of a Zend\Db\TableGateway and you need to actually mock Zend\Db\TableGateway\TableGateway
Change you test code to:
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway',
array('select'), array(), '', false);
Your mock was failing a type-hint because your not mocking the correct class.
Mock objects will extend the class that you are mocking, so they will be an instance of the class being mocked.
I have a Nancy module which uses a function which expects as parameters a string (a captured pattern from a route) and a method group. When trying to pass the parameter directly it will not compile as I "cannot use a method group as an argument to a dynamically dispatched operation".
I have created a second route which attempts to cast the dynamic to a string, but this always returns null.
using System;
using Nancy;
public class MyModule : NancyModule
{
public MyModule()
{
//Get["/path/{Name}/action"] = parameters =>
// {
// return MyMethod(parameters.Name, methodToBeCalled); // this does not compile
// };
Get["/path/{Name}/anotherAction"] = parameters =>
{
return MyMethod(parameters.Name as string, anotherMethodToBeCalled);
};
}
public Response MyMethod(string name, Func<int> doSomething)
{
doSomething();
return Response.AsText(string.Format("Hello {0}", name));
}
public int methodToBeCalled()
{
return -1;
}
public int anotherMethodToBeCalled()
{
return 1;
}
}
Tested with the following class in a separate project:
using System;
using Nancy;
using Nancy.Testing;
using NUnit.Framework;
[TestFixture]
public class MyModuleTest
{
Browser browser;
[SetUp]
public void SetUp()
{
browser = new Browser(with =>
{
with.Module<MyModule>();
with.EnableAutoRegistration();
});
}
[Test]
public void Can_Get_View()
{
// When
var result = browser.Get("/path/foobar/anotherAction", with => with.HttpRequest());
// Then
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
Assert.AreEqual("Hello foobar", result.Body.AsString()); //fails as parameters.Name is always null when cast to a string
}
}
You can find the whole test over on github
I've had similar issues when using 'as' so I tend to use explicitly cast it:
return MyMethod((string)parameters.Name, anotherMethodToBeCalled);
Also I think there was a bug raised with the casing on parameters, but I think it's better to keep them lowercase:
Get["/path/{name}/anotherAction"]
(string)parameters.name
Your code works for me with upper case and lowercase, using the explicit cast.