Correct way to start RSpec-puppet unit tests - unit-testing

I have created a simple Puppet 4 class and a unit test to go along with it as follows (after executing touch metadata.json; rspec-puppet-init while in modules/test/):
# modules/test/manifests/hello_world1.pp
class test::hello_world1 {
file { "/tmp/hello_world1":
content => "Hello, world!\n"
}
}
# modules/test/spec/classes/test__hello_world1_spec.rb
require 'spec_helper'
describe 'test::hello_world1' do
it { is_expected.to compile }
it { is_expected.to contain_file('/tmp/hello_world1')\
.with_content(/^Hello, world!$/) }
end
I can successfully run the unit test by executing rspec spec/classes/test__hello_world1_spec.rb while in modules/test/.
I would now like to proceed to a slightly more advanced class that uses code from another module, namely concat (the module has arleady been installed in modules/concat):
# modules/test/manifests/hello_world2.pp
class test::hello_world2
{
concat{ "/tmp/hello_world2":
ensure => present,
}
concat::fragment{ "/tmp/hello_world2_01":
target => "/tmp/hello_world2",
content => "Hello, world!\n",
order => '01',
}
}
# modules/test/spec/classes/test__hello_world2_spec.rb
require 'spec_helper'
describe 'test::hello_world2' do
it { is_expected.to compile }
# ...
end
When I attempt running this unit test with rspec spec/classes/test__hello_world2_spec.rb while in modules/test I receive an error message that includes:
Failure/Error: it { is_expected.to compile } error during compilation:
Evaluation Error: Error while evaluating a Resource Statement, Unknown
resource type: 'concat'
I suspect the root cause is that rspec cannot find the other module(s), because it has not been told a "modulepath".
My question is this: How exactly am I supposed to start unit tests, especially ones that require access to other modules?

Install the PDK for your platform from its download page. Re-create the module using pdk new module, and pdk new class, or by following the Guide.
Now, I come to what is probably the immediate problem in your code: your code depends on a Puppet Forge module, puppetlabs/concat but you haven't made it available. The PDK module template already has pre-configured puppetlabs_spec_helper to load fixtures for your module.
To tell puppetlabs_spec_helper to get it for you, you need a file .fixtures.yml with the following content:
fixtures:
forge_modules:
stdlib: puppetlabs/stdlib
concat: puppetlabs/concat
Note that you also need puppetlabs/stdlib, because that is a dependency of puppetlabs/concat.
If you want to explore more fixture possibilities, please refer to puppetlabs_spec_helper's docs.
With all of this in place, and integrating the code samples and test content you posted into the initial code skeletons provided by the PDLK, your tests will all pass now when you run:
$ pdk test unit
Note that I have written all about the underlying technologies, in a blog post, showing how to set up Rspec-puppet and more from scratch (ref), and it still appears to be the most up-to-date reference on this subject.
To read more about rspec-puppet in general, please refer to the official rspec-puppet docs site.

Related

jest manual ES6 class mock is not active and I want to understand why

I am having problems using Jest manual mocks (the one in a parallel __mocks__ directory) in my project.
I think I understand how to use it and it actually works fine if I remove a single line in a file specified in the Jest setupFiles array.
In that file a global helper is installed (into global.createComp) that uses the vuex store.
This is a vue + vuex project but even running the stripped down spec using only jest gives unexpected results.
Can somebody look at my minimal reproducible example repo at https://github.com/thenoseman/jest-manual-mock-not-working, do a npm i and npm run test:unit and help me understand why the mock is not active?
You can find the line that need to be commented out in test/unit/support/helpers.js.
Also the README shows a screenshot and further explains what the problem looks like.
setupFiles are evaluated before test files. As the reference states,
A list of paths to modules that run some code to configure or set up the testing environment. Each setupFile will be run once per test file. Since every test runs in its own environment, these scripts will be executed in the testing environment immediately before executing the test code itself.
JavaScript modules are evaluated once on first import. Importing #/store/modules/internetAtHome in helpers.js results in importing original #/api/DslService.
The mock in test file doesn't affect #/api/DslService because it has already been evaluated earlier:
jest.mock("#/api/DslService");
import DslService from "#/api/DslService";
In case helpers.js needs mocked #/api/DslService, jest.mock needs to be moved there.
In case helpers.js needs original #/api/DslService but tests need mocked one, the module (and any module that depends on it) needs to be re-imported with jest.resetModules or jest.isolatedModules:
jest.mock('#/api/DslService');
let DslService;
jest.isolateModules(() => {
DslService = require("#/api/DslService").default;
});
...
For a module that was imported with original implementation and needs to be re-imported as a mock, jest.requireMock can be used, it doesn't need jest.mock('#/api/DslService'):
let DslService = jest.requireMock("#/api/DslService").default;
...

Unit testing Nativescript application logic on a browser

I am trying to set up unit testing for a Nativescript application, run by ng test on a browser. The problem is that whenever there is a tns-core-modules or another plugin import, the module cannot be resolved because of the platform specific files (e.g. "tns-core-modules/application/application.android.js") that never get compiled into the bundle, thus throwing an error like "Module not found: Error: Can't resolve 'tns-core-modules/application'".
I know there is a built-in unit test support in Nativescript. The problem I have with it is that it can't run on CI. I would like to be a ble to have lightweight tests for my business logic, mocking out all platform dependencies.
I have looked for a way to mock the module imports at runtime with no luck. I looked into rewire package but it only runs on node.
I finally managed to get it working. Not a very elegant solution and I have yet to see how much maintenance it requires. Key points here:
Use paths section of the tsconfig.json to add mock import
locations
In the mocks directory create files for any unresolved module
Some nativescript modules are referencing helper functions on global
scope but they're undefined. My solution was to define them in
test.ts like this
window['__decorate'] = () => {};
window['__extends'] = () => {};
window['__metadata'] = () => {};
window['__param'] = () => {};
window['layout_base_1'] = { CSSType: () => {} };
window['Crashlytics'] = {};
window['Fabric'] = {};
You simply can not run NativeScript application on Browser.
In case if you are looking for something like headless mode, Appium has one too, isHeadless in capabilities.
Between, may I know why you think you can not run the {N} unit tests on CI? It should work on CI too, after all it's a machine that runs the same commands based on some trigger.

ReferenceError: ga is not defined [Ionic 2.2 Unit Testing With Karma]

I'm adding unit tests to an Ionic 2.2.0 app I manage, but my Components crash at test-time when they encounter Google Analytics code. I'm using Ionic's official unit testing example as a basis, and my current progress can be seen on our public repo.
My project uses Google Analytics, which is added to the HTML and downloaded at runtime (because we have different keys for development vs production).
The code that initializes Analytics is in my main.ts, and it sets a global variable ga, which is subsequently available throughout the application.
I'm beginning the tests for the app's first page, which uses Analytics. When I run the tests, I'm met with the following error
Component should be created FAILED
ReferenceError: ga is not defined
at new MyBusesComponent (webpack:///src/pages/my-buses/my-buses.component.ts:33:6 <- karma-test-shim.js:138419:9)
at new Wrapper_MyBusesComponent (/DynamicTestModule/MyBusesComponent/wrapper.ngfactory.js:7:18)
at CompiledTemplate.proxyViewClass.View_MyBusesComponent_Host0.createInternal (/DynamicTestModule/MyBusesComponent/host.ngfactory.js:15:32)
........
This is because main.ts doesn't seem to be loaded or executed, and I assume TestBed is doing that purposefully. It's certainly better that I don't have the actual Google Analytics object, but the Component does need a function called ga.
My question, therefore, is as follows: how can I create Google Analytics' ga variable in my test configuration such that it's passed through to my components at test-time?
I've tried exporting a function from my mocks file and adding it to either the imports or providers arrays in my spec file, but to no avail.
I appreciate any advice! Feel free to check my code at our repo I linked to above and ask any followups you need. Thanks!
You declare the var ga but that is just to make TypeScript happy. At runtime, the ga is made global from some external script. But this script is not included in the test.
What you could do is just add the (mock) function to the window for the tests. You could probably do this in your karma-test-shim.js.
window.ga = function() {}
Or if you wanted to test that the component is calling the function with the correct arguments, you could just add the function separately in each test that uses the function. For example
beforeEach(() => {
(<any>window).ga = jasmine.createSpy('ga');
});
afterEach(() => {
(<any>window).ga = undefined;
})
Then in your test
it('..', () => {
const fixture = TestBed.creatComponent(MyBusesComponent);
expect(window.ga.calls.allArgs()).toEqual([
['set', 'page', '/my-buses.html'],
['send', 'pageview']
]);
})
Since you're making multiple calls to ga in the constructor, the Spy.calls will get the argument of all each call and put them in separate arrays.

Laravel workbench unit test

What is the way to test my packages in workbench. If I write a unit test then no classes are autoloaded. So this means that:
<?php
use \Mockery as m;
class ExampleTest extends TestCase {
public function tearDown()
{
m::close();
}
/**
* A basic functional test example.
*
* #return void
*/
public function testShouldReturnValidServer()
{
$mock = m::mock('MailChimp[sendCurl]');
MailChimp::listSubscribe( array( 'id' => 'c79a023ff2', 'email_address' => 'dennieriechelman#gmail.com'));
}
}
results in a error saying that class TestCase is not found. When I add class TestCase to the autoload in my composer.json (the one in my package folder) the class is available. However then I get the next error that "Illuminate\Foundation\Testing\TestCase" is not available etc. etc.
So my question is what should I autoload in my composer.json in my package folder? Everything just like in my main composer.json or is there some other way that I am missing.
I know that in the manuel it says"
You may git init from the workbench/[vendor]/[package] directory and git push your package straight from the workbench! This will allow you to conveniently develop the package in an application context without being bogged down by constant composer update commands.
However I do not understand this. Can someone explain what is meant with this? By the way I am familiar with git. I just do not get the context.
EDIT1
As far I understand now is that you push your package to your repository and then include it in your main composer.json as package. I just do not see how this is helpful when developing. Hopefully I understand this wrong.. :)
EDIT2
I was wrong. You keep your package in workbench until it stable. Just like Nils pointed out below.The question still remains though. How do I create an environment in which I can unit test with the app started. I mean like testing a model where I can mock the facades etc. Or is doing this in the workbench bad practice?
I created a package for this purpose at https://github.com/orchestral/testbench
If you don't mind merging the results of your workbench testing with the results of your main application, you can simply add extra directories to your main phpunit.xml in your laravel root like this:
<testsuites>
<testsuite name="Application Test Suite">
<directory>./app/tests/phpunit/</directory>
<directory>./workbench/vendor/packageOne/tests/</directory>
<directory>./workbench/vendor/packageTwo/tests/</directory>
</testsuite>
</testsuites>
Then in the tests folder of your package, place your phpunit tests as normal, along with the TestCase.php file, adjusting the createApplication() function to be:
<?php
class TestCase extends \Illuminate\Foundation\Testing\TestCase {
public function createApplication()
{
$unitTesting = true;
$testEnvironment = 'testing';
return require './bootstrap/start.php';
}
Make sure your package composer.json auto-loads that TestCase.php file like so:
"autoload": {
"classmap": [
"tests/phpunit/TestCase.php"
]
}
Run composer dump-autoload -o to get everything aligned and then you should be able to run phpunit from your laravel root and it will test both your application and your packages.
Extend from the proper namespace and you should be able to run tests from package dir.
class ExampleTest extends \Illuminate\Foundation\Testing\TestCase {
..
}
See also Laravels neat testing helpers in workbench?

PHPUnit bootstrap in PhpStorm

I am working with Zend Framework 2 and I want to run tests for all of my modules in PhpStorm 5.0.4. I have PhpStorm set up to check for tests in myproject/module and it successfully finds my tests. The problem is that it doesn't read my configuration file within each module, which is needed (it points to a bootstrap file).
Here is the directory structure for a module (source):
/module
/User
/tests
/UserTest
/Model
/UserTest.php
Bootstrap.php
phpunit.xml.dist
TestConfig.php.dist
When I run the test, it gives me an error because Bootstrap.php is not run prior to running UserTest.php. All of the files are correct, because if I cd to /myproject/module/User/tests/ and run phpunit within the Terminal, it works fine.
I would like it to use the configuration (and thereby bootstrap) within each module. I tried to use the --configuration option with a relative path, but I couldn't get it to work.
Here is my current configuration:
Any pointers on how I can run the configuration file (and bootstrap) when a module is being tested? That is, a module has its own configuration file and bootstrap.
Thanks in advance.
PHP Storm 7 assumes that you will only need ONE default bootstrap file and thus does not enable individual bootsrap files DIRECTLY for each PHPUnit test configuration.
However, zf2 conducts tests on a per module basis. Thus, after you set the defaults to the first module the other modules don't work. The way around this is to
Remove the default options in File|Settings|PHP|PHPUnit
You don't have to remove the default configuration file but you must EMPTY OUT and uncheck the default bootstrap file. Just unchecking will not be enough
Go Run|Edit Configurations (there are other shortcuts to this box)
For each module you have to create a test configuration. For example, you'll have the standard Application Module and thus an "Application Module Test" for it, maybe an Admin Module and then an "Admin Module Test" for that
For each test (assuming standard zf2 directory structure)
a. Test Scope: Directory
b. Directory: C:\wamp\www\PROJECT-NAME\module\MODULE-NAME\test
c. Check "Use alternative configuration file:"
d. Enter C:\wamp\www\PROJECT-NAME\module\MODULE-NAME\test\MODULE-NAMETest\phpunit.xml.dist
e. In "Test Runner options", enter "--bootstrap C:\wamp\www\PROJECT-NAME\module\MODULE-NAME\test\MODULE-NAMETest\Bootstrap.php"
Repeat for next module
The issue here is that as long as the default bootsrap field has an entry, phpstorm will add that as default as a --bootstrap option AFTER whatever you put in the case specific Test Runner options. So, no matter what you do, you end up running the wrong bootstrap file everytime except for the first/default test case
Hope this helps
Unless I missed something, you'll have to set up a test configuration for each module. In your case, you have myproject. Instead, you'll want one for each module, and then set up the configuration for each (Use alternative configuration file).
I make use of the environment variables option in the run configuration to to define a value I can use within a global bootstrap.php to pull in requirements specific to a given module or section of the application.
class GlobalBootstrap
{
private static $applicationSections = [
'section_a',
'section_b',
'section_c'
];
public static function init()
{
$localMethod = self::fetchLocalMethod();
if (!is_null($localMethod)) {
self::$localMethod();
} else {
throw new Exception(
__CLASS__
. '::'
. __FUNCTION__
. 'Says: No local method has been defined for this test section'
);
}
}
private static function fetchLocalMethod()
{
$section = getenv('APPLICATION_SECTION');
if (is_null($section) || !in_array($section, self::$applicationSections)) {
return null;
}
$section = preg_replace("/[^a-zA-Z]+/", "", $section);
$method = 'bootstrap' . ucfirst(strtolower($section));
return $method;
}
/**
* Section specific methods
*/
protected static function bootstrapSectiona()
{
require __DIR__ . '/../../{section_a}/module/Test/Bootstrap.php';
}
}
GlobalBootstrap::init();
Any arbitrary variable and value can be created and then referenced in your bootstrap.php using: getevn(VARIABLE_NAME); This saves a lot of long-winded configuration in PHPStorm, but culd potentially get equally as complex if you're relying on a lot of differing bootstrap functionality.