Rails 4 Apipie - How to document a parent controller class? - ruby-on-rails-4

I'm using APIPIE to document an API that I'm implementing.
I have a class called BaseController that implements the methods create, update, destroy, show, etc, in a generic way, so any controller that extends BaseController will not need to implement those methods.
With Apipie, I'm documenting like this
class API::V1::SampleController < API::V1::BaseController
api! "Create a sample"
param ....
def create
super
end
end
I'm doing this to all controllers that extend BaseController, but I don't think it is a good idea. Is there any way to define the documentation in BaseController itself, so that Apipie generates documentation for every controller in my application that extends it?

Related

How to write a test for bundle which it depends on some entity

I've been working on a grid bundle for Symfony. The bundle receives a Symfony Entity and based on that, it renders a gridview.
something like this:
class IndexController extends AbstractController
{
public function __construct(GridBuilder $grid, BookGrid $userGrid)
{
$this->grid = $grid;
$this->userGrid = $userGrid;
}
/**
* #Route("/")
*/
public function index()
{
return $this->render('index.html.twig', [
'grid' => $this->grid->build($this->userGrid),
]);
}
}
BookGrid is a class extended from BaseGridConfigurator which it has to implement getEntity method:
class BookGrid extends BaseGridConfigurator
{
public function getEntity()
{
return Book::class;
}
}
The GridBuilder uses the EntityRepository (in this case BookRepository) to get the entity's metadata such as fields, Repository and QueryBuilder.
If I want to write unit test for the bundle, I need an entity class to pass it to GridBuilder. I think there are two approaches to solve this problem.
Create a mock Entity and Repository
Create a real Entity and Repository class inside my test directory
My question is which approach is correct? and is there any other way to test a bundle that it depends on an entity?
Thank you
Assuming getEntity (which perhaps should be renamed to getEntityClass) is used by GridBuilder to obtain the desired entity repository from the entity manager internally, wouldn't it be easier to have BaseGridConfigurator provide access to the entity repository directly? E.g. getEntityRepository(): EntityRepository instead of getEntity(): string. I can imagine this would significantly reduce the amount of mocking you would have to do if all you need is the entity repository.
In any case, the Symfony documentation on the subject of unit testing entity repositories advice against unit testing entity repository dependent implementations in general.
But if you have to, I would focus on a design where your implementation needs as few contact points with the entity repository as possible in order to minimize the amount of mocking that the test requires. But would still opt for mocking over stubbing regardless.

Unit testing lit-element mixins

What are the ways to unit test a lit-element mixin? I have a simple mixin that just modifies the firstUpdated lifecycle event of a lit-element:
const mixin = sup => class extends sup {
firstUpdated() {
super.firstUpdated();
// do something else.
}
}
So basically, the usage is:
class MyElement extends mixin(LitElement) {
...
}
I'm not really sure how to handle the unit tests for this.
UPDATE
I could probably create a test element that extends the mixin, i.e. MyElement, and then test the element's firstUpdated function. Is that the only way to test this or are there better ways to do this?
Creating a test element class to apply the mixin to is the right approach. There are two ways to think about mixins that show this:
A mixin is only a potential class - you don't actually have anything to test until you apply it to a superclass to generate a concrete class.
A mixin is a function. You need to call a function to test it.

How to create application-wide Scala functions which perform web service calls in Play 2.4?

I want to create a LinkedinApi class, containing functions which execute web service requests to Linkedin servers. These functions need to be accessible from anywhere in the Play app code. The easiest way I've written such API classes in the past, was to have them declared as an object. Then LinkedinApi.myPublicFunction() is available from anywhere.
The problem is that I don't see how I can declare my LinkedinApi class as an object. It would use Play 2.4's web services, and this is done by adding #Inject()(ws: WSClient) to the class declaration. Something like object LinkedinApi #Inject()(ws: WSClient) extends Controller.
The problem is that the line above doesn't compile. It seems that #Inject can only be used with class declarations, not with object.
So how can I create application-wide API functions which perform web service calls?
I think you should define your LinkedinApi as a service and inject it where needed:
#Singleton
class LinkedinApi #Inject()(ws: WSClient) {
//...
//linkedin stuff
//...
}
and inject as:
#Singleton
class SomeController #Inject()(linkedinApi:LinkedinApi) {
//...
}

Laravel Tests pass to model to View

I'm mocking my repository correctly, but in cases like show() it either returns null so the view ends up crashing the test because of calling property on null object.
I'm guessing I'm supposed to mock the eloquent model returned but I find 2 issues:
What's the point of implementing repository pattern if I'm gonna end up mocking eloquent model anyway
How do you mock them correctly? The code below gives me an error.
$this->mockRepository->shouldReceive('find')
->once()
->with(1)
->andReturn(Mockery::mock('MyNamespace\MyModel)
// The view may call $book->title, so I'm guessing I have to mock
// that call and it's returned value, but this doesn't work as it says
// 'Undefined property: Mockery\CompositeExpectation::$title'
->shouldReceive('getAttribute')
->andReturn('')
);
Edit:
I'm trying to test the controller's actions as in:
$this->call('GET', 'books/1'); // will call Controller#show(1)
The thing is, at the end of the controller, it returns a view:
$book = Repo::find(1);
return view('books.show', compact('book'));
So, the the test case also runs view method and if no $book is mocked, it is null and crashes
So you're trying to unit test your controller to make sure that the right methods are called with the expected arguments. The controller-method fetches a model from the repo and passes it to the view. So we have to make sure that
the find()-method is called on the repo
the repo returns a model
the returned model is passed to the view
But first things first:
What's the point of implementing repository pattern if I'm gonna end up mocking eloquent model anyway?
It has many purposes besides (testable) consisten data access rules through different sources, (testable) centralized cache strategies, etc. In this case, you're not testing the repository and you actually don't even care what's returned, you're just interested that certain methods are called. So in combination with the concept of dependency injection you now have a powerful tool: You can just switch the actual instance of the repo with the mock.
So let's say your controller looks like this:
class BookController extends Controller {
protected $repo;
public function __construct(MyNamespace\BookRepository $repo)
{
$this->repo = $repo;
}
public function show()
{
$book = $this->repo->find(1);
return View::make('books.show', compact('book'));
}
}
So now, within your test you just mock the repo and bind it to the container:
public function testShowBook()
{
// no need to mock this, just make sure you pass something
// to the view that is (or acts like) a book
$book = new MyNamespace\Book;
$bookRepoMock = Mockery::mock('MyNamespace\BookRepository');
// make sure the repo is queried with 1
// and you want it to return the book instanciated above
$bookRepoMock->shouldReceive('find')
->once()
->with(1)
->andReturn($book);
// bind your mock to the container, so whenever an instance of
// MyNamespace\BookRepository is needed (like in your controller),
// the mock will be loaded.
$this->app->instance('MyNamespace\BookRepository', $bookRepoMock);
// now trigger the controller method
$response = $this->call('GET', 'books/1');
$this->assertEquals(200, $response->getStatusCode());
// check if the controller passed what was returned from the repo
// to the view
$this->assertViewHas('book', $book);
}
//EDIT in response to the comment:
Now, in the first line of your testShowBook() you instantiate a new Book, which I am assuming is a subclass of Eloquent\Model. Wouldn't that invalidate the whole deal of inversion of control[...]? since if you change ORM, you'd still have to change Book so that it wouldn't be class of Model
Well... yes and no. Yes, I've instantiated the model-class in the test directly, but model in this context doesn't necessarily mean instance of Eloquent\Model but more like the model in model-view-controller. Eloquent is only the ORM and has a class named Model that you inherit from, but the model-class as itself is just an entity of the business logic. It could extend Eloquent, it could extend Doctrine, or it could extend nothing at all.
In the end it's just a class that holds the data that you pull e.g. from a database, from an architecture point of view it is not aware of any ORM, it just contains data. A Book might have an author attribute, maybe even a getAuthor() method, but it doesn't really make sense for a book to have a save() or find() method. But it does if you're using Eloquent. And it's ok, because it's convenient, and in small project there's nothing wrong with accessing it directly. But it's the repository's (or the controller's) job to deal with a specific ORM, not the model's. The actual model is sort of the outcome of an ORM-interaction.
So yes, it might be a little confusing that the model seems so tightly bound to the ORM in Laravel, but, again, it's very convenient and perfectly fine for most projects. In fact, you won't even notice it unless you're using it directly in your application code (e.g. Book::where(...)->get();) and then decide to switch from Eloquent to something like Doctrine - this would obviously break your application. But if this is all encapsulated behind a repository, the rest of your application won't even notice when you switch between databases or even ORMs.
So, you're working with repositories, so only the eloquent-implementation of the repository should actually be aware that Book also extends Eloquent\Model and that it can call a save() method on it. The point is that it doesn't (=shouldn't) matter if Book extends Model or not, it should still be instantiable anywhere in your application, because within your business logic it's just a Book, i.e. a Plain Old PHP Object with some attributes and methods describing a book and not the strategies how to find or persist the object. That's what repositories are for.
But yes, the absolute clean way is to have a BookInterface and then bind it to a specific implementation. So it could all look like this:
Interfaces:
interface BookInterface
{
/**
* Get the ISBN.
*
* #return string
*/
public function getISBN();
}
interface BookRepositoryInterface()
{
/**
* Find a book by the given Id.
*
* #return null|BookInterface
*/
public function find($id);
}
Concrete implementations:
class Book extends Model implements BookInterface
{
public function getISBN()
{
return $this->isbn;
}
}
class EloquentBookRepository implements BookRepositoryInterface
{
protected $book;
public function __construct(Model $book)
{
$this->book = $book;
}
public function find($id)
{
return $this->book->find($id);
}
}
And then bind the interfaces to the desired implementations:
App::bind('BookInterface', function()
{
return new Book;
});
App::bind('BookRepositoryInterface', function()
{
return new EloquentBookRepository(new Book);
});
It doesn't matter if Book extends Model or anything else, as long as it implements the BookInterface, it is a Book. That's why I bravely instantiated a new Book in the test. Because it doesn't matter if you change the ORM, it only matters if you have several implementations of the BookInterface, but that's not very likely (sensible?), I guess. But just to play it safe, now that it's bound to the IoC-Container, you can instantiate it like this in the test:
$book = $this->app->make('BookInterface');
which will return an instance of whatever implementation of Book you're currently using.
So, for better testability
Code to interfaces rather than concrete classes
Use Laravel's IoC-Container to bind interfaces to concrete implementations (including mocks)
Use dependency injection
I hope that makes sense.

Reference model in template beyond request / page scope, in Play! 1.2.4

I came across at this thread, does anybody know how to do this in Play! 1.2.4? Thanks.
The same effect is not quite possible, I think. You can of course reference classes in your Models package by using fully qualified names (models.YourModel) to access enumerations, for example.
Anything you add in the renderArgs scope in your controller will be available in the template, plus there are some implicit objects that are always in use (see Play framework documentation for full listing). For example the play.Play object contains all kinds of useful stuff.
With #Before and #With annotations you can set up a controller used by multiple other controllers to have objects "globally" available - see Interceptions.
Even better, create a super controller extending Controller. Afterwards, let all your controllers extends your SuperController.
class SuperController extends Controller {
#Before
public static function before() {
// Set global variables using renderArgs
}
}
class MyController extends SuperController {
public function myMethod() {
// Do whatever your method does.
}
}
Check out the documentation : http://www.playframework.org/documentation/1.2.4/controllers#result