testng - HTTP REST testing behind Login - http

I have setup a project for testing HTTP REST application using testNG / Maven / Springs RestTemplate.
I use it to do functional testing, multiple calls to the REST application are contained within suites to mimic user processes.
This is working fine.
Know we have turned on authentication.
Question is how to do this with testNG? How can i (only once) login for my test suite.
I can use a #BeforeSuite and call the loginpage, login and catch the cookie needed for all other requests. But where do i store this cookie so all test cases can add it?
I propably have to add some code to the tests to add the cookie of course....but how do i get hold of that?
I looked into #parameter and #dataprovider, but these seem not help me much...
Any help/suggestion is much appreciated.

I have created a workable solution.
What I have done is worked with a singleton object and with the #dataprovider, to get the data to the test:
The dataprovider creates a singleton object.
The singleton object calls the login page in its creation and will after every call from the different tests return the cookie information.
Maybe it is a bit of a hack, but it works.

The Singleton solution is somewhat heavy-handed as it prevents any parallelization of tests in the future.
There are some ways to solve this problem. One is to pass a ITestContext instance to your #BeforeSuite/#BeforeTest and #BeforeClass configuration methods and put/get the parameters via the test context in every instance:
public class Test {
/** Property Foo is set once per Suite */
protected String foo;
/** Property Foo is set once per Test */
protected String bar;
/**
* As this method is executed only once for all inheriting instances before the test suite starts this method puts
* any configuration/resources needed by test implementations into the test context.
*
* #param context test context for storing test conf data
*/
#BeforeSuite
public void beforeSuite(ITestContext context) {
context.setAttribute("foo", "I was set in #BeforeSuite");
}
/**
* As this method is executed only once for all inheriting instances before the test starts this method puts any
* configuration/resources needed by test implementations into the test context.
*
* #param context test context for storing test conf data
*/
#BeforeTest(alwaysRun = true)
public void beforeTest(ITestContext context) {
context.setAttribute("bar", "I was set in #BeforeTest");
}
/**
* This method is run before the first method of a test instance is started and gets all required configuration from
* the test context.
*
* #param context test context to retrieve conf data from.
*/
#BeforeClass
public void beforeClass(ITestContext context) {
foo = (String) context.getAttribute("foo");
bar = (String) context.getAttribute("bar");
}
}
This solution works even if the #BeforeSuite/Test/Class methods are in a superclass of the actual test implementation.

If you are delegating the login on Spring Security and your backend does not store state (means that only authorizes isolated requests) then you do not need to test it. This means that you can disable authentication (cookie obtaining) in your tests. This way you decouple the test itself from the authorization.
But if you do not want to do this. And If you organise your tests in suites you can set a private member. The cookie will be the header auth in the response.
#TestSuite
public void mySuite {
private String cookie;
#BeforeSuite public void login() {
// Obtain cookie
this.cookie = cookie;
}
////// Rest of suite
Another way to look at it is to execute login as a part of your test.
I do not know any other way more elegant of do it.

Related

Laravel service provider for sharing a variable in all views

I want to share a variable in all views but i'm not sure if this is the right way to do it? I have made a service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Worktype;
class ShareWorktypesInViewsProwider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
$worktypes = Worktype::all();
view()->share('worktypes', $worktypes);
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
but i still get an error in my view. Do i need to register my service provider or it should work out of the box?
Firstly, for such a small piece of code I wouldn't worry about creating a brand new service provider. I would just add the above to your AppServiceProvider. Also, you code inline the above as well:
view()->share('worktypes', Worktype::all());
As for registering a provider. Literally all you have to do is go to config/app.php, find the providers array and add your provider to it.
In your can you would add:
App\Providers\ShareWorktypesInViewsProwider::class,
The documentation for it:
https://laravel.com/docs/5.3/providers#registering-providers
Hope this helps!
A more recent update on this. While #Rwd solution works great, you may run into difficulties as the service provider is run every single request.
As a result, you'll end up requesting Worktype from the database regardless of whether you're on a view, etc.
The best way to achieve this now is by using Laravel View composers.
By adding the below into your service provider, you'll only call the Worktype::all() when needed within a view.
view()->composer('*', function($view) {
$view->with(['worktypes' => Worktype::all()]);
});
Although make sure to use some caching otherwise it'll get called for every view!

Proper way to test a Symfony2 Service with Doctrine

I'm struggling to find the correct way to unit test my symfony 2 services which use doctrine or other common services.
What i have done so far:
In my understanding the controller actions should:
be as short as possible
take the request
execute required methods from injected services
build a response out of this
is a service itself
To accomplish a lightweight action, i try to encapsule the logic into a separate service which gets injected into the controller.
This works nicely expect for testing everything.
Here my current code:
Controller
class SearchController
{
// search_helper, request and templating are controller-injected
protected $search_helper;
protected $request;
protected $templating;
// ...
public function searchAction()
{
$searchterm = strtolower($this->request->query->get('q'));
$result = $this->search_helper->findSamples($searchterm);
// Found a single result. Redirect to this page
if (is_string($result))
{
return new RedirectResponse($result, 301);
}
return new Response($this->templating->render('AlbiSampleBundle:Search:index.html.twig', array('results' => $result)));
}
}
SearchService
class SearchHelper
{
// doctrine, session and min_query_len are controller-injected
protected $doctrine;
protected $session;
protected $min_query_len;
// ...
public function findSamples($searchterm)
{
if (strlen($searchterm) < $this->min_query_len)
{
$msg = 'Your search must contain at least 3 characters!';
$this->session->getFlashBag()->add('error', $msg);
return false;
}
$em = $this->doctrine->getManager();
$results = $em->getRepository('AlbiSampleBundle:Sample')->findPossibleSamples($searchterm);
// Execute a more advanced search, if std. search don't delivers a result
// ...
return $results;
}
}
How can i test this code correctly?
The repository is tested with phpunit_db and a inmemory sqlite database ✓
The action can be tested through a simple functional test ✓
What's left is the logic in the search-service. e.g. the findSamples method
My first thought was to mock the dependencies (in fact that was one of the main aspects in separating the dependencies), but you not only have to mock the doctrine object, but also the entitymanager and the repository.
$em = $this->doctrine->getManager();
$results = $em->getRepository('AlbiSampleBundle:Sample')->findPossibleSamples($searchterm);
I think there must be a better solution. Not only would this mocking need many LOCs, it also doesn't feel right. The test would be unnecessarily coupled really tight to the SUT.
EDIT
Here is a sample test i came up with. Using mock objects.
The test won't work. I realized it would take much more mock-objects and i got the feeling this isn't the right way.
The test fails because SessionMock->getFlashbag doesn't return a flashbag with add method.
doctrine->getManager returns no EntityManager. The EntityManager has no getRepository method. And the repository is missing findPossibleSamples.
class SearchHelperTest extends \PHPUnit_Framework_TestCase
{
private $router;
private $session;
private $doctrine;
public function setUp()
{
parent::setUp();
// ...
}
public function testSearchReturnValue()
{
$search_service = $this->createSearchHelper();
$this->assertFalse($search_service->findSamples('s'));
}
protected function createSearchHelper()
{
return new SearchHelper($this->doctrine, $this->router, $this->session, 3);
}
protected function getDoctrineMock()
{
return $this->getMock('Doctrine\Bundle\DoctrineBundle\Registry', array('getManager'), array(), '', false);
}
protected function getSessionMock()
{
return $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('getFlashBag'), array(), '', false);
}
protected function getRouterMock()
{
return $this->getMock('Symfony\Component\Routing\Router', array('generate'), array(), '', false);
}
}
Hope the community can help me, writing well tested code :)
cheers
For your specific example I would argue that the validation of the $searchterm doesn't really belong in your service - at the very least a service should never depend on the session. There are ways you could move the session out of the service and leave the validation in but personally I would use symfony validation for this i.e. have a SampleSearchType for the form that uses itself as the data class and hang the validation off that in validation.yml (or using annotations as appropriate).
Once that validation is taken out, what's left from your question is another findX() method to be added to the repository (there's no reason why repository methods can't call and build on each other) which you already know how to test.
Having said that, I still agree that with Symfony there is a general issue of how to test services in isolation from injected services. With respect to testing in isolation from the persistence layer I've avoiding trying to do this so far. My business layer services are so tightly coupled with the persistence layer that the cost of trying to test them independently is not worthwhile (what logic there is consists mainly of making related db updates or sending emails for which symfony provides it's own decoupling mechanism). I'm not sure if this is because I'm doing it wrong or because the apps I'm working on are light on business logic!
To isolate service tests from dependencies other than persistence I've tried:
Overriding service classes with mocked versions in the configuration. Issue - you don't want to do this for functional tests which means you have to have tests scripts which update the configuration and/or change the config to run individual tests. Advantage - you can run the same test as an isolated unit test and as an integration test by flipping the config
(Warning: nasty hack!) providing a setter method to replace an injected service with a mocked version from the test program.
(Not yet tried) Directly instantiate the service being tested, passing mock dependencies in on construction.
With respect to isolating from the persistence layer the only approach that makes sense to me is to abstract it out of the service to be tested into a wrapper service which contains no additional logic. The wrapper service could then be mocked using one of the above approaches (or hopefully a better solution that someone else is going to suggest?!)
EDIT: to address the issue of complexity of mocking dependencies - very occasionally this may be unavoidable but in general this is an indication that the design needs revisiting. This is one of the strengths of TDD - it strongly encourages simplified design and decoupling of components:
No service should need to be dependent upon the session object. This is not good practice and can always be avoided. Worst case the example method could return mixed values and if the result is not an array it's assumed to be an error message, although there are better alternatives.
Sometimes dependencies are unnecessary (code more naturally belongs elsewhere) or too general (I would question the necessity of injecting high level objects like doctrine or e.g. the container into anything other than test helpers).
If there is a complex dependency to mock (such as on multiple classes from the persistence layer) abstract it out into a wrapper which is far simpler to mock than the complex dependency.

Symfony 2 functional tests with mocked services

I have a controller I'd like to create functional tests for. This controller makes HTTP requests to an external API via a MyApiClient class. I need to mock out this MyApiClient class, so I can test how my controller responds for given responses (e.g. what will it do if the MyApiClient class returns a 500 response).
I have no problems creating a mocked version of the MyApiClient class via the standard PHPUnit mockbuilder: The problem I'm having is getting my controller to use this object for more than one request.
I'm currently doing the following in my test:
class ApplicationControllerTest extends WebTestCase
{
public function testSomething()
{
$client = static::createClient();
$apiClient = $this->getMockMyApiClient();
$client->getContainer()->set('myapiclient', $apiClient);
$client->request('GET', '/my/url/here');
// Some assertions: Mocked API client returns 500 as expected.
$client->request('GET', '/my/url/here');
// Some assertions: Mocked API client is not used: Actual MyApiClient instance is being used instead.
}
protected function getMockMyApiClient()
{
$client = $this->getMockBuilder('Namespace\Of\MyApiClient')
->setMethods(array('doSomething'))
->getMock();
$client->expects($this->any())
->method('doSomething')
->will($this->returnValue(500));
return $apiClient;
}
}
It seems as though the container is being rebuilt when the second request is made, causing the MyApiClient to be instantiated again. The MyApiClient class is configured to be a service via an annotation (using the JMS DI Extra Bundle) and injected into a property of the controller via an annotation.
I'd split each request out into its own test to work around doing this if I could, but unfortunately I can't: I need to make a request to the controller via a GET action and then POST the form it brings back. I'd like to do this for two reasons:
1) The form uses CSRF protection, so if I just POST directly to the form without using the crawler to submit it, the form fails the CSRF check.
2) Testing that the form generates the correct POST request when it is submitted is a bonus.
Does anyone have any suggestions on how to do this?
EDIT:
This can be expressed in the following unit test that does not depend on any of my code, so may be clearer:
public function testAMockServiceCanBeAccessedByMultipleRequests()
{
$client = static::createClient();
// Set the container to contain an instance of stdClass at key 'testing123'.
$keyName = 'testing123';
$client->getContainer()->set($keyName, new \stdClass());
// Check our object is still set on the container.
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Passes.
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Passes.
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Fails.
}
This test fails, even if I call $client->getContainer()->set($keyName, new \stdClass()); immediately before the second call to request()
When you call self::createClient(), you get a booted instance of the Symfony2 kernel. That means, all config is parsed and loaded. When now sending a request, you let the system do it's job for the first time, right?
After the first request, you may want to check what went on, and therefore, the kernel is in a state, where the request is sent, but it's still running.
If you now run a second request, the web-architecture requires, that the kernel reboots, because it already ran a request. This reboot, in your code, is executed, when you execute a request for the second time.
If you want to boot the kernel and modify it before the request is sent to it (like you want), you have to shutdown the old kernel-instance and boot a fresh one.
You can do that by just rerunning self::createClient(). Now you again have to apply your mock, as you did the first time.
This is the modified code of your second example:
public function testAMockServiceCanBeAccessedByMultipleRequests()
{
$keyName = 'testing123';
$client = static::createClient();
$client->getContainer()->set($keyName, new \stdClass());
// Check our object is still set on the container.
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName)));
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName)));
# addded these two lines here:
$client = static::createClient();
$client->getContainer()->set($keyName, new \stdClass());
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName)));
}
Now you may want to create a separate method, that mocks the fresh instance for you, so you don't have to copy your code ...
I thought I'd jump in here. Chrisc, I think what you want is here:
https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer
I agree with your general approach, configuring this in the service container as a parameter is really not a good approach. The whole idea is to be able to mock this dynamically during individual test runs.
The behaviour you are experiencing is actually what you would experience in any real scenario, as PHP is share nothing and rebuilds the whole stack on each request. The functional test suite imitates this behaviour to not generate wrong results. One example would be doctrine, which has a ObjectCache, so you could create objects, not save them to the database and your tests would all pass because it takes the objects out of the cache all the time.
You can solve this problem in different ways:
Create a real class which is a TestDouble and emulates the results you would expect from the real API. This is actually very easy: You create a new MyApiClientTestDouble with the same signature as your normal MyApiClient, and just change the method bodies where needed.
In your service.yml, you alright might have this:
parameters:
myApiClientClass: Namespace\Of\MyApiClient
service:
myApiClient:
class: %myApiClientClass%
If this is the case, you can easily overwrite which class is taken by adding the following to your config_test.yml:
parameters:
myApiClientClass: Namespace\Of\MyApiClientTestDouble
Now the service container will use your TestDouble when testing. If both classes have the same signature, nothing more is needed. I don't know if or how this works with the DI Extras Bundle. but I guess there is a way.
Or you could create a ApiDouble, implementing a "real" API which behaves in the same way your external API does but returns test data. You would then make the URI of your API handled by the service container (e.g. setter injection) and create a parameters variable which points to the right API (the test one in case of dev or test and the real one in case of the production environment).
The third way is a bit hacky, but you can always make a private method inside your tests request which first sets up the container in the right way and then calls the client to make the request.
I do not know if you ever found out how to fix your problem. But here is the solution i used. This is also good for other people finding this.
After a long search for the problem with mocking a service between multiple client requests i found this blog post:
http://blog.lyrixx.info/2013/04/12/symfony2-how-to-mock-services-during-functional-tests.html
lyrixx talk about how the kernel shutsdown after each request making the service overrid invalid when you try to make another request.
To fix this he creates a AppTestKernel used only for the function tests.
This AppTestKernel extends the AppKernel and only apply some handlers to modifie the Kernel:
Code examples from lyrixx blogpost.
<?php
// app/AppTestKernel.php
require_once __DIR__.'/AppKernel.php';
class AppTestKernel extends AppKernel
{
private $kernelModifier = null;
public function boot()
{
parent::boot();
if ($kernelModifier = $this->kernelModifier) {
$kernelModifier($this);
$this->kernelModifier = null;
};
}
public function setKernelModifier(\Closure $kernelModifier)
{
$this->kernelModifier = $kernelModifier;
// We force the kernel to shutdown to be sure the next request will boot it
$this->shutdown();
}
}
When you then need to override a service in your test you call the setter on the testAppKernel and applies the mock
class TwitterTest extends WebTestCase
{
public function testTwitter()
{
$twitter = $this->getMock('Twitter');
// Configure your mock here.
static::$kernel->setKernelModifier(function($kernel) use ($twitter) {
$kernel->getContainer()->set('my_bundle.twitter', $twitter);
});
$this->client->request('GET', '/fetch/twitter'));
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
}
}
After following this guide i had some problems getting the phpunittest to startup with the new AppTestKernel.
I found out that the symfonys WebTestCase (https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php)
Takes the first AppKernel file it finds. So one way to get out of this is to change the name on the AppTestKernel to come before AppKernel or to override the method to take the TestKernel Instead
Here i overrride the getKernelClass in the WebTestCase to look for a *TestKernel.php
protected static function getKernelClass()
{
$dir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : static::getPhpUnitXmlDir();
$finder = new Finder();
$finder->name('*TestKernel.php')->depth(0)->in($dir);
$results = iterator_to_array($finder);
if (!count($results)) {
throw new \RuntimeException('Either set KERNEL_DIR in your phpunit.xml according to http://symfony.com/doc/current/book/testing.html#your-first-functional-test or override the WebTestCase::createKernel() method.');
}
$file = current($results);
$class = $file->getBasename('.php');
require_once $file;
return $class;
}
After this your tests will load with the new AppTestKernel and you will be able to mock services between multiple client requests.
Based on the answer by Mibsen you can also set this up in a similar way by extending the WebTestCase and overriding the createClient method. Something along these lines:
class MyTestCase extends WebTestCase
{
private static $kernelModifier = null;
/**
* Set a Closure to modify the Kernel
*/
public function setKernelModifier(\Closure $kernelModifier)
{
self::$kernelModifier = $kernelModifier;
$this->ensureKernelShutdown();
}
/**
* Override the createClient method in WebTestCase to invoke the kernelModifier
*/
protected static function createClient(array $options = [], array $server = [])
{
static::bootKernel($options);
if ($kernelModifier = self::$kernelModifier) {
$kernelModifier->__invoke();
self::$kernelModifier = null;
};
$client = static::$kernel->getContainer()->get('test.client');
$client->setServerParameters($server);
return $client;
}
}
Then in the test you would do something like:
class ApplicationControllerTest extends MyTestCase
{
public function testSomething()
{
$apiClient = $this->getMockMyApiClient();
$this->setKernelModifier(function () use ($apiClient) {
static::$kernel->getContainer()->set('myapiclient', $apiClient);
});
$client = static::createClient();
.....
Make a mock:
$mock = $this->getMockBuilder($className)
->disableOriginalConstructor()
->getMock();
$mock->method($method)->willReturn($return);
Replace service_name on mock-object:
$client = static::createClient()
$client->getContainer()->set('service_name', $mock);
My problem was to use:
self::$kernel->getContainer();
I faced with the same problem in Symfony 4.4.
After reading
Create mocks in api functional testing with Symfony
I found a solution - self::ensureKernelShutdown()
...
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Passes.
self::ensureKernelShutdown()
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Passes.
...

How to prevent Fixtures from being reloaded between tests with CakePHP and PHPUnit

How do you prevent a CakePHP 2.0 test case, which extends CakeTestCase (uses PHPUnit), from reloading fixtures between tests?
Background: There is a set of integration tests which we have written with CakePHP 2.0 using PHPUnit. We have extended the test case class from the standard CakeTestCase. For this set of tests, we have a bunch of fixtures setup to populate the data from the database. Naturally, these tests take a long time to run. Basically, all of the time is coming from Cake unloading and re-loading all of the fixtures between tests.
All of the tests act as READ only. We are just issuing find calls to the database and testing the logic among a set of class interactions based on those results. In fact, the tests can be boiled down to:
class ALongRunningTest extends CakeTestCase {
public $fixtures = array('app.class1', 'app.class2', ... 'app.class8');
/**
* #dataProvider provider
* #test
*/
public function checkCompositionLogic($val1, $val2, $val3) {
// internally calls class1 and class3
$data = $this->ModelX->generateComplexStructure($val1);
// internally calls other classes & models, which touch the
// other loaded fixtures
$results = $this->ModelY->checkAllWhichApply($val2, $data);
$this->assertEquals($val3, $results);
}
public function provider() {
return array(
array(stuff, stuff1, stuff2),
array(x_stuff, x_stuff1, x_stuff2),
array(y_stuff, y_stuff1, y_stuff2),
array(z_stuff, z_stuff1, z_stuff2),
array(a_stuff, a_stuff1, a_stuff2),
// More test cases
);
}
}
I've not been able to find anything on how to prevent this. I saw in the CakeTestCase class a public variable autoFixtures with a comment that says if you change it to false it won't load the fixtures. It makes a note stating that you have to load them manually. However, I see no documentation on how to actually load them manually.
Strictly speaking, CakePHP is correct in the way that it works. Tests shouldn't be dependent upon each other, so that database is reset between each test case. You could even argue that it should be reset between each test method, but the overhead would be even more noticeable.
However, since you're doing read only actions on the database, you could remove all the references to fixtures in your test cases and set up your database entries before you run the test suite (e.g. import it from an SQL file).
Or you could create a custom test suite that adds a whole load of data, e.g:
class AllTest extends CakeTestSuite {
public static function suite() {
self::loadDB();
$suite = new CakeTestSuite('All tests');
$suite->addTestDirectoryRecursive(TESTS . 'Case');
return $suite;
}
public static function loadDB() {
//Do some set up here using your models
}
}
The advantage of doing it that was is that if you ever had to introduce tests that do write to the database, you could run them under a separate test suite.

How do I set query cache on a call issued by the seam engine

#In
Identity identity;
Boolean newValue = identity.hasPermission(target, action);
Any call to the above method also does a "select role from Role r" call, which is called from the underlying seam engine. How do I set the query cache for this call as a query hint (e.g. org.hibernate.cacheable flag) so that it doesn't get called again.
Note: Role information is never bound to change, hence I view this as a unnecessary sql call.
I am not in hibernate, but as this question is still unanswered: we extended the standard Identity class of seam for several reasons. You might want to extend it as well to help you caching the results.
As this cache is session scoped, it will have the possible benefit that it will be reloaded when the user logs on/off again - but this depends on your requirements.
Best regards,
Alexander.
/**
* Extended Identity to implement i.e. caching
*/
#Name("org.jboss.seam.security.identity")
#Scope(SESSION)
#Install(precedence = Install.APPLICATION)
#BypassInterceptors
#Startup
public class MyIdentity extends Identity {
// place a concurrent hash map here
#Override
public boolean hasPermission(Object name, String action) {
// either use the use the cached result in the hash map ...
// ... or call super.hasPermission() and cache the result
}
}

Resources