I'm writing functional / controller tests for a ZF3 application (driven by PHPUnit and zendframework/zend-test). Like this:
public function testWhatEver()
{
$this->dispatch('/');
$this->assertResponseStatusCode(Response::STATUS_CODE_200);
}
It's working pretty well. But now I got a case, where I need to test the application with multiple mutually exclusive configs.
E.g., the case "authentication": The application provides multiple authentication methods (let's say: AuthA, AuthB,AuthC). (That is configurable via setting of the auth.type's value in the config file.) I want to test each of them. That means, it's not enough to have special test configs in the /config/autoload/test/*{local|global}.php. I need to be able to manipulate them for every test (before I call the dispatch(...) method).
How to manipulate the application configs for / from controller tests (on the fly)?
If no better solution can be found, a possible workaround might be to edit the config file (by using file_put_contents(...) or something like this) before every test. But it's a bit ugly (and slow).
In general I see no really nice solution for this problem. But there some more or less acceptable workaround:
Workaround 1: manipulating the according config file for every test
$configs = file_get_contents(...)
searchByRegexAndManipulateConfigs(...)
file_put_contents(...)
It's much effort and would make the testing slower (due to reading from / writing to the filesystem).
Workaround 2: simple files with only one config value
We can create files like config.auth.type.php or config.auth.type.txt (one per config value t keep the file really simple) and to use inclue or file_get_contents(...) call as value in the config. The the value in the file needs to be manipulated before the test execution.
It's a bit less effort (we don't need to write complex RegEx), but might make the test considerably slower, since every application request would start by reading an additional file.
Workaround 3: passing configs values through GLOBALS
It's the simplest and fastest variant. We just save the needed value into a global variable and read it in the config (file's) array. After the test we remove the variable:
AuthBTest
...
protected function setUp() // or setUpBeforeClass()
{
parent::setUp();
$GLOBALS['appTestConfigs']['auth.type'] = 'AuthA';
}
protected function tearDown() // or tearDownAfterClass()
{
parent::tearDown();
unset($GLOBALS['appTestConfigs']);
}
...
/config/autoload/test/local.php
return [
'auth' => [
'type' => isset($GLOBALS['appTestConfigs']['auth.type']) ? $GLOBALS['appTestConfigs']['auth.type'] : 'AuthA',
],
];
Related
I am writing unit tests for some async sections of my code (returning Futures) that also involves the need to mock a Scala object.
Following these docs, I can successfully mock the object's functions. My question stems from the fact that withObjectMocked[FooObject.type] returns Unit, where async tests in scalatest require either an Assertion or Future[Assertion] to be returned. To get around this, I'm creating vars in my tests that I reassign within the function sent to withObjectMocked[FooObject.type], which ends up looking something like this:
class SomeTest extends AsyncWordSpec with Matchers with AsyncMockitoSugar with ResetMocksAfterEachAsyncTest {
"wish i didn't need a temp var" in {
var ret: Future[Assertion] = Future.failed(new Exception("this should be something")) // <-- note the need to create the temp var
withObjectMocked[SomeObject.type] {
when(SomeObject.someFunction(any)) thenReturn Left(Error("not found"))
val mockDependency = mock[SomeDependency]
val testClass = ClassBeingTested(mockDependency)
ret = testClass.giveMeAFuture("test_id") map { r =>
r should equal(Error("not found"))
} // <-- set the real Future[Assertion] value here
}
ret // <-- finally, explicitly return the Future
}
}
My question then is, is there a better/cleaner/more idiomatic way to write async tests that mock objects without the need to jump through this bit of a hoop? For some reason, I figured using AsyncMockitoSugar instead of MockitoSugar would have solved that for me, but withObjectMocked still returns Unit. Is this maybe a bug and/or a candidate for a feature request (the async version of withObjectMocked returning the value of the function block rather than Unit)? Or am I missing how to accomplish this sort of task?
You should refrain from using mockObject in a multi-thread environment as it doesn't play well with it.
This is because the object code is stored as a singleton instance, so it's effectively global.
When you use mockObject you're efectibly forcefully overriding this var (the code takes care of restoring the original, hence the syntax of usign it as a "resource" if you want).
Because this var is global/shared, if you have multi-threaded tests you'll endup with random behaviour, this is the main reason why no async API is provided.
In any case, this is a last resort tool, every time you find yourself using it you should stop and ask yourself if there isn't anything wrong with your code first, there are quite a few patterns to help you out here (like injecting the dependency), so you should rarely have to do this.
I am currently using following pattern when creating tests with QTest.
One test class per production class.
If a class has some 'global' setting run the test class multiple times with each such setting.
Each production class method has one test method.
Each test method has _data method.
Each _data method specify settings and data to be used and names the cases.
This last point somewhat bothers me because I am not passing just data but also data to be used for initialising that particular test. Sometimes it looks weird and even though my tests are short they are not all that intuitive because of the initialisation logic.
The alternative pattern I know of is to split each test method (breaking my rule #3) based on this initialisation needs. On one hand it would eliminate a lot of _data test methods but it would also make the test classes much bigger and no longer easily relatable to the production class (the naming would help though). Most google tests are written like this.
Another alternative would be to use global state of the object much like I treat global settings. If the object is either valid or invalid then it would not be part of each _data method but rather setting of the test class that would run in either configuration.
My main concern is maintainability. With my current approach I sometimes struggle to understand the nuances of the settings I pass to the tests and I need some sensible way to separate them and not to burden myself even more by it.
For global settings you run the test class multiple times, so IMHO doing the same for local settings doesn't really "violate" your rule #3, it is more an extension of rule #2.
Alternatively you could make the initialization routine another thing that is part of the test data.
Something like
private slots:
void someMethodTest_data()
{
QTest::addColumn<QByteArray>("settings");
//....
QTest::addRow("case1") << "settings1" << ....
}
void someMethodTest()
{
Q_FETCH(QByteArray, settings);
const QByteArray initMethod = QTest::currentTestFuntion() + "_init_" + settings;
QMetaObject::invokeMethod(this, initMethod.constData(), Qt::DirectConnect);
// commence test
}
protected slots:
void someMethodTest_init_settings1();
Main question is self explanatory, but I'll give some side examples:
I'm having trouble figuring out databases, though it seems I can work out config with ServiceManager stuff
I want to use constants for cookie names, so I can change them easily if there are collisions. Current, I'm calling $config = new \Zend\Config\Config(include $_SERVER['DOCUMENT_ROOT'] . '/../config.php'); every time I want access to my global config.php file. A lot of previous solutions were in Zend 1 (eg Zend_Registry). Is this the right way to do it? It seems a little unwieldy using that over and over.
Is there a way to utilize a Module's configuration file to set module-wide-variables/constants?
Unless I'm completely missing it, there's no application.ini in Zend 2
Storing recaptcha public/private keys
I'm also using my config file for session-variables (same idea as $_SESSION[CONST_NAME]), which makes it really clumsy with the config file above. Is it better to hardcode the session names? Like:
$container = new Zend\Session\Container('auth');
$container->offsetSet('user', $user);
... // instead of
$container = new Zend\Zession\Container($config['auth']['containername']);
$container->offsetSet($config['auth']['user'], $user);
All configuration from each module.config.php or Module.php are put together into a big pot. You can easily access those via $this->getServiceLocator()->get('config')
When it comes down to constants, they should be placed inside the respective classes. Like
class UserStorage {
const SESSIONCONTAINERNAME = 'blubbusersession';
}
That way you can call \My\User\Model\UserStorage::SESSIONCONTAINERNAME whenever you need this info
As far as your example is concerned thought, there should be almost no need to var-code your session-container-name because the information from your modules session-data should be made available via your modules Service-Classes. But if you still need it, see aboves example.
Furthermore i think it may be a good idea for you to check out how zf-commons\ZfcUser does things
I have added a cache layer to my project . now I wonder if I could unit test methods that manipulate cache ? or is there a better way to test Layer's logic ?
I just want to check the process , for example :
1- when the item is not in the cache , method should hit the database
2- the next time method should use cache
3- when a change is made to database , cache should be cleared
4- if data retrieved from databse is null , it shouldn't be added to cache
I want to ensure that the logic I have placed into the methods are working as expected .
I'm presuming the cache is a third party cache? If so, I would not test it. You're testing someone else's code otherwise.
If this caching is so important you need to test it, I'd go with an integration or acceptance test. In other words, hit the page(s)/service(s) in question and check the content that way. By the very definition of what you wish to test, this is not a unit test.
On the flip side, if the cache is one you've rolled yourself, you'll easily be able to unit test the functionality. You might want to check out verification based testing in order to test the behavior of the cache, as apposed to actually checking stuff is added/removed from the cache. Check out mocking for ways to achieve this.
To test for behaviour via Mock objects (or something similar) I'd do the following - although your code will vary.
class Cacher
{
public void Add(Thing thing)
{
// Complex logic here...
}
public Thing Get(int id)
{
// More complex logic here...
}
}
void DoStuff()
{
var cacher = new Cacher();
var thing = cacher.Get(50);
thing.Blah();
}
To test the above method I'd have a test which used a mock Cacher. You'd need to pass this into the method at runtime or inject the dependency into the constructor. From here the test would simply check that cache.Get(50) is invoked. Not that the item is actually retrieved from the cache. This is testing the behavior of how the cacher should be used, not that it is actually caching/retrieving anything.
You could then fall back to state based testing for the Cacher in isolation. E.g you add/remove items.
Like I said previously, this may be overkill depending on what you wish to do. However you seem pretty confident that the caching is important enough to warrant this sort of testing. In my code I try to limit mock objects as much as possible, though this sounds like a valid use case.
I'm in my module file. I want to define some complex variables for use throughout the module. For simple things, I'm doing this:
function mymodule_init() {
define('SOME_CONSTANT', 'foo bar');
}
But that won't work for more complex structures. Here are some ideas that I've thought of:
global:
function mymodule_init() {
$GLOBALS['mymodule_var'] = array('foo' => 'bar');
}
variable_set:
function mymodule_init() {
variable_set('mymodule_var', array('foo' => 'bar'));
}
property of a module class:
class MyModule {
static $var = array('foo' => 'bar');
}
Variable_set/_get seems like the most "drupal" way, but I'm drawn toward the class setup. Are there any drawbacks to that? Any other approaches out there?
I haven't seen any one storing static values that are array objects.
For simple values the drupal way is to put a define in the begining of a modules .module file. This file is loaded when the module is activated so that is enough. No point in putting it in the hook_init function.
variable_set stores the value in the database so don't run it over and over. Instead you could put it in your hook_install to define them once. variable_set is good to use if the value can be changed in an admin section but it's not the best choice to store a static variable since you will need a query to fetch it.
I think all of those methods would work. I have never used it in this fashion, but I believe the context module (http://drupal.org/project/context) also has its own API for storing variables in a static cache. You may want to check out the documentation for the module.
It's always a good practice to avoid globals. So that makes your choice a bit easier.
If you err towards a class, you'll be writing code that is not consistent with the D6 standards. There are a lot of modules that do it but I personally like to keep close to the Drupal core so I can understand it better. And code that's written in different styles through the same application can have an adverse effect on productivity and maintenance.
variable_set() and define() are quite different. Use the former when you can expect that information to change (a variable). Use the latter for constants. Your requirements should be clear as which one to use.
Don't worry too much about hitting the database for variable_set/get. If your software is written well, it should not effect performance hardly at all. Performance work arounds like that should only be implemented if your applications has serious performance issues and you've tried everything else.