How can globally I mock/replace components in integration tests? - ember.js

I have a component "nested" which makes a web request, and I'm using this component from another component "parent".
I'm trying to write some integration tests for "parent", but they are failing as the "nested" component's web requests are failing.
Instead of mocking out the requests, I was just hoping to mock some of the "nested" functionality to prevent the web request. This is easily achievable with reopen, but of course this will cause the tests for "nested" to fail.
Does anyone know if there is a way that I can either stub pieces of "nested", or maybe use the registry to replace "nested" with an extended class?

To swap out a component, just for the purpose of a single test module, simply register a custom component to replace the original (only for the scope of the test module):
moduleForComponent('component-under-test', 'description', {
integration: true,
beforeEach() {
this.container.registry.register('component:nested-component', NestedComponent.extend({
modifiedFunction() {
}
}));
}
});

Related

Ember Test for parent route with method calls

I was brought in on the "back-end" of a project and asked to help write tests for an app. I am very new to Ember and need just a little help getting started. We are trying to provide unit test for the routes, so we can have a bit more molecular scope over the app, instead of acceptance test. I have looked at some tutorials and went through every possible scenario that I could think of. I just need a bit of jumpstart.
Here is the part of the route.js for this route.
down stream of this parent route, we have another nested route that shows a list of contacts and when a user clicks on a show button it calls "model" and returns that variable "rec" for the template and the url
export default Route.extend(ScrollTo, {
flashMessages: service(),
model: function(params) {
let rec= this.store.peekRecord('contact', params.contact_id);
return rec;
},
actions: {
saveContact: function() {
let model = this.currentRouteModel();
model
.save()
.then(() => {
//this.refresh();
//this.setModelHash();
this.flashMessages
.success(`Saved Contact: ${model.get('title')}`);
//this.transitionTo('contacts');
});
}
Here is pre-generated code for the test. I really haven't made any modifications, because I really didn't know where to start.
This app doesn't have a back-end, it's design is to take in information and provide a iso file based on whatever standard the user wants.
I am sure I need to provide some mock data for the test and send that to the method, but again I am not sure what Qunit parts I use.
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | contact/show', function(hooks) {
setupTest(hooks)
test('it exists', function(assert) {
var route = this.owner.lookup('route:contact/show');
assert.ok(route, 'contact.show route works');
});
});
I struggled with this as well when I first moved to frontend testing. With a few years experience I'm confident in saying you shouldn't unit test the route objects in this way. Instead the testing of an ember app should focus on two types of tests.
What ember calls integration tests (but are actually closer to UI unit tests)
Acceptance tests
Integration tests on components allow you to get into the smaller details and edge cases and they can be super valuable.
What I think you want in this case is actually an acceptance test.
If your testing experience is at all like mine it will feel like you're testing too many things at first, but these types of tests where the browser actually loads the entire application have the most value in hunting down bugs and are the most maintainable over time.

Grails Unit Testing Issues

I am having issues while testing my grails controllers, as it depends on one service which seems not to be injected. I tried several ways (for ex. Extending classess like grailsunitestcase, specification) but I keep getting errors. The thing is that that service variable is null and I cant test my controller index method (which calls a render view) due to the exception...
I really need to know how to do this but I don't have a clue where to start...
Unit tests are just that. There is no grails 'environment' surrounding your controller. If the controller makes use of a service which is normally injected, you have to mock that service yourself.
#TestFor(SomeController)
#Mock([SomeService])
class SomeControllerSpec extends Specification
def "test some method"() {
given:
def mockService = mockFor(SomeService)
mockService.demand.someServiceMethod() { ->
return something
}
controller.someService = mockService.createMock()
when:
controller.someControllerMethod()
then:
// whatever checks are appropriate
}
}

How do enable the format.js helpers in Ember Unit tests

I am using Ember with formatjs to internationalize my application, and ember-cli to build it all.
When I generate a component with
ember g component some-component
Ember also creates a test that checks that the component renders. However, if I use the intl-get helper from formatjs in the component template, the unit test fails.
So how can I register the custom helpers that formatjs creates for a unit test?
I first tried to add the intl-get helper:
moduleForComponent('some-component', {
needs: ['helper:intl-get']
});
However, this just fails inside intl-get when it tries to access "intl:main". I would like for the intl initializer to run, but I am not sure if there is even application setup. Or is it some way to just mock those methods using sinon?
My current workaround is to just delete the 'it renders' tests. But I would like for these tests to pass as well, so I can further test rendering later if I want.
Try:
moduleForComponent('some-component', {
integration: true
});

Laravel 5 isolated controller testing

I'm trying to unit test my controllers in Laravel 5, but have serious issues wrapping my head around it. It seems as I have to trade the great short-hand functions and static classes for dependency injected equivalents if I actually want to do isolated unit testing.
First off, what I see in the documentation as "Unit testing", is not unit testing to me. It seems more like functional testing. I can not test a controller function isolated, as I will have to go through the entire framework, and will need to actually seed my database if I have any code interacting with my database.
So, in turn, I want to test my controllers isolated of the framework. This is however proving to be quite difficult.
Let's look at this example function (I've kept out some parts of this function for the sake of the question):
public function postLogin(\Illuminate\Http\Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->has('remember')))
{
return redirect()->intended($this->redirectPath());
}
}
Now, the problem arises in the final lines. Sure, I can mock the Request instance that's sent to the function, that's no issue. But how am I going to mock the Auth class, or the redirect function? I need to rewrite my class/function with dependency injection like this:
private $auth;
private $redirector;
public function __construct(Guard $auth, \Illuminate\Routing\Redirector $redirector)
{
$this->auth = $auth;
$this->redirector = $redirector;
}
public function postLogin(\Illuminate\Http\Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if ($this->auth->attempt($credentials, $request->has('remember')))
{
return $this->redirector->intended($this->redirectPath());
}
}
And I end up with a convoluted unit test, full of mocks:
public function testPostLoginWithCorrectCredentials()
{
$guardMock = \Mockery::mock('\Illuminate\Contracts\Auth\Guard', function($mock){
$mock->shouldReceive('attempt')->with(['email' => 'test', 'password' => 'test'], false)->andReturn(true);
});
$redirectorMock = \Mockery::mock('\Illuminate\Routing\Redirector', function($mock){
$mock->shouldReceive('intended')->andReturn('/somePath');
});
$requestMock = \Mockery::mock('\Illuminate\Http\Request', function($mock){
$mock->shouldReceive('only')->with('email', 'password')->andReturn(['email' => 'test', 'password' => 'test']);
$mock->shouldReceive('has')->with('remember')->andReturn(false);
});
$object = new AuthController($guardMock, $redirectorMock);
$this->assertEquals('/somePath', $object->postLogin($requestMock));
}
Now, if I had any more complex logic that would, for example, use a model, I'd have to dependency inject that as well, and mock it in my class.
To me, it seems like either, Laravel isn't providing what I want it to do, or my testing logic is flawed. Is there any way I can test my controller functions without getting out-of-control testing functions and/or having to depedency inject standard Laravel classes, available to me anyways in my controller?
You shouldnt be trying to unit test controllers. They are designed to be functional tested via calling them through the HTTP protocol. This is how controllers are designed, and Laravel provides a number of framework assertions you can include in your tests to ensure they work as expected.
But if you want to unit test the application code contained within the controller, then you should actually consider using Commands.
Using Commands allows you to extracte the application logic from your controller into a class. You can then unit test the class/command to ensure you get the results expected.
You can then simply call the command from the controller.
In fact the Laravel documentation tells you this:
We could put all of this logic inside a controller method; however, this has several disadvantages... it is more difficult to unit-test the command as we must also generate a stub HTTP request and make a full request to the application to test the purchase podcast logic.

Unit testing Zend controllers with mock models and services

I've read a lot of Zend controller testing tutorials but I can't find one that explains how to test a controller that uses models and mocking those models.
I have the following controller action:-
function indexAction(){
// Get the cache used by the application
$cache = $this->getCache();
// Get the index service client and model
$indexServiceClient = new IndexServiceClient($this->getConfig());
$indexModel = $this->_helper->ModelLoader->load('admin_indexmodel', $cache);
$indexModel->setIndexServiceClient($indexServiceClient);
// Load all the indexes
$indexes = $indexModel->loadIndexes();
$this->view->assign('indexes', $indexes);
}
At the moment I have a very basic test case:-
public function testIndexActionRoute() {
$this->dispatch( '/admin/index' );
$this->assertModule('admin', 'Incorrect module used');
$this->assertController('index', 'Incorrect controller used');
$this->assertAction('index', 'Incorrect action used');
}
This test works but it's calling the real models and services, which sometimes means it times out and fails on the test environment. In order to properly unit test just the controller I need to have mocks and expectations for IndexServiceClient and IndexModel - how is this done?
Well, since not many replies I am seeing here, I'll try to add my 2cents(potentially arguable).
Answer written below is my IHMO and very subjective(and I think not very useful, but here we go anyway)
I think controllers are not a good fit unit testing. Your business logic layer, models etc. is what is unitestable.
Controllers are connected with UI and bring system together so to speak - hence to me they are a better fit for integration and UI testing - something that packages such as Selenium are used for.
To my mind testing should be easy enough to implement such that total effort for testing implementation is adequate to the returns of it. Wiring up all dependencies for a controller seems to me(with my limited knowledge of course) a bit too much of a task.
The other way to think about it is - what is actually going on in your controllers. Again IHMO it supposed to be primarily a glue level between your business logic and your UI. If you're putting a lot of business logic into controller it will have an adverse effect(for instance it won't be easily unitestable..).
This is all sort of theory of course. Hopefully someone can provide a better answer and actually show how to easily wire up a controller for unit tests!
One possible solution that a colleague put forward is to use a Zend Controller Action Helper to inject mock dependencies. This should work in theory but I've yet to extensively test this method
Here is an example of doing it this way.
class Mock_IndexModel_Helper extends Zend_Controller_Action_Helper_Abstract {
private $model;
public function __construct($model) {
$this->model = $model;
}
/**
* Init hook
*/
public function init() {
$this->getActionController()->setIndexModel( $this->model );
}
}
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase {
public $bootstrap = BOOTSTRAP;
public function setUp(){
parent::setUp();
}
/**
* Test the correct module/controller/action are used
*/
public function testIndexAction() {
$mockIndexModel = $this->getMock("IndexModel");
Zend_Controller_Action_HelperBroker::addHelper(new Mock_IndexModel_Helper($mockIndexModel));
$this->dispatch( '/admin/index' );
$this->assertModule('admin', 'Incorrect module used');
$this->assertController('index', 'Incorrect controller used');
$this->assertAction('index', 'Incorrect action used');
}
}