how to unit test of this function using TDD ? - javascript

I am new for unit test and TDD method so could you help me please.
function calculate(a, b) {
var sum = a + b;
var sub = a - b;
return { sum: sum, sub: sub };
}

With jest you can do it like this :
describe('calculation', ()=> {
let result
beforEach(()=>{
result = calculate(2, 3)
})
it('returns the correct sum', (){
expect(result.sum).toBe(5)
})
it('returns the correct sub', (){
expect(result.sub).toBe(-1)
})
})

it('checks calculations', function() {
var calculate = require('./example.js');
expect(calculate(1, -1).sum).toBe(0);
expect(calculate(1, -1).sub).toBe(2);
});
Save the file as a .js and use npm test.
I am assuming that you are using jestjs.
You can definitely add other test conditions depending upon your understanding of the function.

A very different answer here: the huge problem with testing such code manually is the fact that it is hard to tell when you wrote enough tests covering different cases.
An alternative approach here: instead of specifying only expected results you step back and identify the contracts that your method under test should adhere to.
And then you use one of the quickcheck-based frameworks, such as JSVerify. You give those rules to the tool - and then the tool creates random data and runs test cases. And it case it finds violations of the contract, it will then try to "minimize" the test input - so that you, in the end receive a message "when you use this data x,y,z then rule A is violated".
It is a very different approach compared to "normal" TDD and unit testing, but especially for such kind of functionality it can be a very effective additional thing to do.

Related

Nyc coverage is not working for me when using functional approach with e.g. ramda

So my code is this:
const handler = (event = { body: {} }) => {
if (isEventEmpty(event)) {
return Promise.resolve({})
}
const getPayload = R.compose(
R.flatten,
R.map(x => transformRecord(x)),
R.pluck('Stuff'),
R.path(['body'])
)
const processEvent = R.compose(
toPromise,
R.ifElse(isEventEmpty, R.always({}), getPayload)
)
return processEvent(event)
}
module.exports = { handler }
With if (isEventEmpty(event)) { coverage is 66.67% which is fine. But without that if coverage will be 0. Notice that I use R.ifElse composable from Ramda. All unit tests pass that's why I'm not showing them, but coverage report shows 0% Branches 0/1. With imperative if branch I have 2/3 in coverage report.
Does anyone have also experience NOT using if-else branching (or loops) when writing their code? Seems that nyc is only looking in if-else, for/while branches or I might be wrong.
I don't think code coverage isn't working, it is simply becoming less useful in a functional programming setting.
This is what I've shared in a presentation at work:
Given yes-no.js:
module.exports = bool => bool === true ? 'yes' : 'no';
And yes-no-fp.js
const {ifElse, equals, always} = require('ramda');
module.exports = ifElse(equals(true),always('yes'),always('no'));
And the following tests:
test.true(yesOrNo(true) === 'yes');
test.true(yesOrNoFp(true) === 'yes');
Then you get the following code coverage:
As you can see for the same test:
The functional programming version reports 100% branch coverage
The "imperative" version reports 50% branch coverage
Personally I think this is a good thing as I always say this to my team mates: code coverage is a tool not a rule. It should help you devise fewer but better tests. It should never be an aim.
If 100% code coverage is your aim then there is a chance that nobody in code review will flag that you're missing a test case. Why should they if you have successfully covered the entire code?
So how do you write better tests?
I'm not sure there's a single answer to that question but I'd definitely recommend that you look into property-based testing. It can help you write more thorough tests for sure.
If you're interested I found this article extremely useful.

How to skip or ignore programmatically a suite in CodeceptJS

As the test suite grows I need to be able to run something in BeforeSuite() which will connect to external suite and skip the suite if an external resource is unavailable.
Feature('External Server');
BeforeSuite((I) => {
// Check if server is available and skip all scenarios if it is not
});
Scenario('Login to the server', (I) => {
// Do not run this if the server is not available
})
I understand I could probably set a variable, but I think it would be nice if there was a way to tell the runner that a suite has been skipped.
The goal is to have a suite marked as skipped in the output eg:
Registration --
✓ Registration - pre-checks in 4479ms
✓ Registration - email validation in 15070ms
✓ Registration - password validation in 8194ms
External Server -- [SKIPPED]
- Login to the server [SKIPPED]
maybe prepend x before every scenario in your feature? example xScenario. I don't think codecept supports something similar to only for features. it currently works with scenarios only as far as I know.
you can use
Scenario.skip
in your step definition to skip a scenario.
Note: if any steps have been executed before skipping then it will still show it in the report
https://codecept.io/basics/#todo-test
My answer is compiled from a number of comments on the CodeceptJS github and stackoverflow. However, I can't recall the exact links or comments which helped me derive this solution, it's been at least a year, maybe two, since I started and have slowly modified this.
Edit: Found the github thread - https://github.com/codeceptjs/CodeceptJS/issues/661
Edit2: I wrote a post about "selective execution" (which avoids tagging unwanted tests with skip status) https://github.com/codeceptjs/CodeceptJS/issues/3544
I'll add a snippet at the bottom.
I'm on CodeceptJS 3.3.6
Define a hook file (eg: skip.js) and link it to your codeceptjs.conf.js file.
exports.config = {
...
plugins: {
skipHook: {
require: "../path/to/skip.js",
enabled: true,
}
}
...
}
The basic code in skip.js is
module.exports = function () {
event.dispatcher.on(event.test.before, function (test) {
const skipThisTest = decideSkip(test.tags);
if (skipThisTest) {
test.run = function skip() {
this.skip();
};
return;
}
});
};
I've defined a decision function decideSkip like so:
function decideSkip(testTags) {
if (!Array.isArray(testTags)) {
output.log(`Tags not an array, don't skip.`);
return false;
}
if (testTags.includes("#skip")) {
output.log(`Tags contain [#skip], should skip.`);
return true;
}
if (
process.env.APP_ENVIRONMENT !== "development" &&
testTags.includes("#stageSkip")
) {
output.log(`Tags contain [#stageSkip], should skip on staging.`);
return true;
}
}
(Mine is a bit more complicated, including evaluating whether a series of test case ids are in a provided list but this shows the essence. Obviously feel free to tweak as desired, the point is a boolean value returned to the defined event listener for event.test.before.)
Then, using BDD:
#skip #otherTags
Scenario: Some scenario
Given I do something first
When I do another thing
Then I see a result
Or standard test code:
const { I } = inject();
Feature("Some Feature");
Scenario("A scenario description #tag1 #skip #tag2", async () => {
console.log("Execute some code here");
});
I don't know if that will necessarily give you the exact terminal output you want External Server -- [SKIPPED]; however, it does notate the test as skipped in the terminal and report it accordingly in allure or xunit results; at least insofar as CodeceptJS skip() reports it.
For "selective execution" (which is related but not the same as "skip"), I've implemented a custom mocha.grep() utilization in my bootstrap. A key snippet is as follows. To be added either to a bootstrap anonymous function on codecept.conf.js or some similar related location.
const selective = ["tag1", "tag2"];
const re = selective.join("|");
const regex = new RegExp(re);
mocha.grep(regex);

Unit Testing Assertion when using Mocks

I am writing a unit test using mocks and would like to ask an opinion. My specific example is mocking the "window" object, however the problem could occur in other scenarios.
To note, I am reverse engineering the unit tests, TDD is a new style which we are adopting here.
The module I am testing is one that will return the hash part of the URL and grab parameters from it. For example if the hash value was:
#param=value&param2=value2
Then the module would return an object like:
{
param: 'value',
param2: 'value2'
}
The first unit test I am writing is one which returns the hash value without the hash. Here is the method:
getCurrentHash: function() {
return window.location.hash.slice(1);
},
I have mocked the window object to set window.location.hash equal to #param=value&param2=value2
I am expecting getCurrentHash to return param=value&param2=value2 in this particular instance.
The window object is a dependency on the hash module, I have switched the path when running the tests to use the mocked version.
The Question
Should unit test explicitly test against the mocked data like this:
tdd.test('getCurrentHash', function () {
var currentHash = hash.getCurrentHash();
currentHash.should.equal('param=value&param2=value2');
});
Or should the unit test be testing the format of the return value, like this:
tdd.test('getCurrentHash', function () {
var currentHash = hash.getCurrentHash();
currentHash.should.not.contain('#');
currentHash.should.be.a('string');
currentHash.should.have.length.above(0);
});
This question came about due to the fact that the mock might change. If for example we decided to add spaces into our mock we would end up amending it to param=value&param2=value2+withspace. This would then make the test fail and I would need to change the test to:
tdd.test('getCurrentHash', function () {
var currentHash = hash.getCurrentHash();
currentHash.should.equal('param=value&param2=value2+withspace');
});
However, in the case of the second test which is more generic, I would not need to change the unit test.
I have read a few articles including the ones listed below, but I couldn't find any detailed reasoning on what an assertion should assert
http://martinfowler.com/articles/mocksArentStubs.html
Unit Tests: How to Assert? Asserting results returned or that a method was called on a mock?
you want to test the behaviour you want to see from the thing you are testing. Your behaviour is (based on the implementation) that the window locations hash value minus the '#' char is returned. So you should test things like:
when no has values exist, nothing is returned (but no error is returned (unless you explicitly want that))
The expected value is returned when a value exists
your second test has little value IMHO as I could change the implementation to this and the tests would still pass.
getCurrentHash: function() {
return "bob";
}
This makes the test fairly useless. your tests exist to verify the behaviour of the system. So write tests that set up happy path conditions, failure cases and edge cases and have them verify that things behave in the way you expect.

How can I test unit test my jQuery-based code?

I have following code in a file named index.js. I want to test some functions in it add, print being the prime one.
(function($){
"use strict";
$(function(){
var add = function(a, b){
// ...
},
print = function(str){
// ...
},
setup = function(){
// ...
},
init = function(){
// ...
};
setup();
init();
});
})(jQuery);
How can I do so?
Does this way of coding add any security on client side? All I have is code that runs on the client side. No server involvement what-so-ever.
I tried :
var outerObj = (function(greet){
var innerObj = (function(){
return {test: function(){ console.log(greet); }}
})();
return innerObj;
})("hi");
outerObj.test();
but, in my case, innerObj line has a $ on the right hand of equal sign, making console yell error that shouts $(...) is not a function.
Which I agree, it's an array of single document object.
Check out var a = (function(){ var val = $(function(){return 10;})(); })(); in any jquery enabled web-page's console, for the error.
Even if I ditch outer shell and bring $(function() {}); out. How am I gonna test that?
It's still an object, still an error.
What kind of testing can I perform, unit, bdd, etc. and how?
I don't quite see what pattern you're using here - it seems like a bit of an anti-pattern. It's not testable, and doesn't expose any behaviour for real world use. I'd highly recommend reading (or at least skimming) Javascript Design Patterns by Addy Osmani, available for free.
For Unit Testing, I've always found a happy midpoint between the simple constructor pattern and revealing module pattern easiest to work with.
var x = function($){
"use strict";
var add = function(a, b){
alert('add');
},
print = function(str){
return 1;
},
setup = function(){
alert('setup');
},
init = function(){
alert('init');
};
init();
setup();
return {
add: add,
print: print
};
};
var y = new x(jQuery);
In the above example, y will have the add and print methods available. Check out a sample test on this fiddle.
As a side note, I've recently been using the excellent QUnit framework for setting up and running my JS Unit Tests. It's by the jQuery Team, so you know it's gonna be good ;).
I'd also suggest checking out BlanketJS for reporting on coverage, and qunit-parameterize for setting up multiple test cases.
For what its worth, BDD isn't a 'test type', but a way of working. For what tests you should have - Unit Tests and Integration Tests are the most important 2, IMO. I use QUnit for Unit Tests, and Selenium with NUnit for Integration Testing.

Faking/Mocking a Javascript object for Unit Tests

Quite a large portion of my work day to day involves working with Dynamics CRM and writing JS to extend the functionality on the forms.
Most clientside interaction in Dynamics involves using an object provided for you when the form loads, which is just Xrm. So you might have something like:
function OnLoad() {
Xrm.Page.getAttribute('name').setValue('Stackoverflow!');
var x = Xrm.Page.getAttribute('name').getValue();
}
I tend to write a wrapper for the Xrm object, mainly because it is a lot easier than remembering some of the chaining and end up with something like:
function WrappedXrm(realXrm) {
var xrm = realXrm;
this.getValue(name) {
return xrm.getAttribute(name).getValue();
}
}
//and then use it as so
var myXrm = new FakeXrm(Xrm);
var myXrmValue = myXrm.getValue('Name');
I am trying out QUnit and wondering how would I go about unit testing in this scenario?
Obviously the example above is a single line, it might not be worth testing it. But assume there was some business logic there that I wanted to test.
The only way I can see is doing some set up before each test along the lines of
var fakeXrm = {};
fakeXrm.Page = {};
fakeXrm.Page.getAttribute = function(name) {
var tempAttr = {};
tempAttr.getValue = function() {
return 'A fake value';
}
}
And then testing on 'A fake value' being returned, but this doesn't 'feel' right to me at all.
Where am I going wrong?
Using Mocks
So in this case, you want to create an instance of WrappedXrm, and pass it an object that mocks the Xrm from your lib ; you need a mock of Xrm.
A first alternative is to write it like you did (which is perfectly valid, if you know what the interface of Xrm is.)
Some libraries like sinon.js or "spies" in the jasmine framework can help you write code like ;
create a 'mock' Xrm, to configure what it should return
create an instance of WrappedXrm with this mock
call the getValue method of WrappedXrm
check that some method was called on the mock
But in the case of javascript, simply created a object that has just the right properties might be okay.
Note that your tests would break if the structure of the "real" Xrm object changes ; that might be what bother's you, but that's always the risk with mocks...
Using the real implementation
If you don't want to test against a mock (which might make sense in case of a wrapper), then maybe you can write the mimimal code that would create an actual Xrm object in your qunit html page (Maybe hardcoding markup ? I don't know the library, so...)
Hoping this helps.

Categories