Is it possible to test simple variable inside function? I would like to test only part of my function. For example
function x(number) {
let len = number.toString().length
return 'End'
}
I would like to test if len variable is set properly. Is it possible?
It is not possible to write assertions for the private internals of js functions.
I've personally found this barrier to encourage better tests to be written. The existing tests continue to enforce that internal changes work correctly.
Writing tests against internal function behavior increases the maintenance effort of the code being tested. Since the tests become more tightly coupled to the source code, they'll need more attention when making changes.
If you find yourself wanting to test some internal behavior, it's recommended to create another function. For example
export class Math extends React.Component {
...
computeLen(input) {
return input.toString().length;
}
function x(number) {
let len = computeLen(number)
return 'End'
}
}
You can now assert that whatever logic is being used to calculate the sample length works as expected for various inputs. This extraction of logic often makes the function x(number) more readable as well.
Related
I am reading a book where it says one way to handle impure functions is to inject them into the function instead of calling it like the example below.
normal function call:
const getRandomFileName = (fileExtension = "") => {
...
for (let i = 0; i < NAME_LENGTH; i++) {
namePart[i] = getRandomLetter();
}
...
};
inject and then function call:
const getRandomFileName2 = (fileExtension = "", randomLetterFunc = getRandomLetter) => {
const NAME_LENGTH = 12;
let namePart = new Array(NAME_LENGTH);
for (let i = 0; i < NAME_LENGTH; i++) {
namePart[i] = randomLetterFunc();
}
return namePart.join("") + fileExtension;
};
The author says such injections could be helpful when we are trying to test the function, as we can pass a function we know the result of, to the original function to get a more predictable solution.
Is there any difference between the above two functions in terms of being pure as I understand the second function is still impure even after getting injected?
An impure function is just a function that contains one or more side effects that are not disenable from the given inputs.
That is if it mutates data outside of its scope and does not predictably produce the same output for the same input.
In the first example NAME_LENGTH is defined outside the scope of the function - so if that value changes the behaviour of getRandomFileName also changes - even if we supply the same fileExtension each time. Likewise, getRandomLetter is defined outside the scope - and almost certainly produces random output - so would be inherently impure.
In second example everything is referenced in the scope of the function or is passed to it or defined in it. This means that it could be pure - but isn't necessarily. Again this is because some functions are inherently impure - so it would depend on how randomLetterFunc is defined.
If we called it with
getRandomFileName2('test', () => 'a');
...then it would be pure - because every time we called it we would get the same result.
On the other hand if we called it with
getRandomFileName2(
'test',
() => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(Math.floor(25 * Math.random()))
);
It would be impure, because calling it each time would give a different result.
There's more than one thing at stake here. At one level, as Fraser's answer explains, assuming that getRandomLetter is impure (by being nondeterministic), then getRandomFileName also is.
At least, by making getRandomFileName2 a higher-order function, you at least give it the opportunity to be a pure function. Assuming that getRandomFileName2 performs no other impure action, if you pass it a pure function, it will, itself, transitively, be pure.
If you pass it an impure function, it will also, transitively, be impure.
Giving a function an opportunity to be pure can be useful for testing, but doesn't imply that the design is functional. You can also use dependency injection and Test Doubles to make objects deterministic, but that doesn't make them functional.
In most languages, including JavaScript, you can't get any guarantees from functions as first-class values. A function of a particular 'shape' (type) can be pure or impure, and you can check this neither at compile time nor at run time.
In Haskell, on the other hand, you can explicitly declare whether a function is pure or impure. In order to even have the option of calling an impure action, a function must itself be declared impure.
Thus, the opportunity to be impure must be declared at compile time. Even if you pass a pure 'implementation' of an impure type, the receiving, higher-order function still looks impure.
While something like described in the OP would be technically possible in Haskell, it would make everything impure, so it wouldn't be the way you go about it.
What you do instead depends on circumstances and requirements. In the OP, it looks as though you need exactly 12 random values. Instead of passing an impure action as an argument, you might instead generate 12 random values in the 'impure shell' of the program, and pass those values to a function that can then remain pure.
There's more at stake than just testing. While testability is nice, the design suggested in the OP will most certainly be impure 'in production' (i.e. when composed with a proper random value generator).
Impure actions are harder to understand, and their interactions can be surprising. Pure functions, on the other hand, are referentially transparent, and referential transparency fits in your head.
It'd be a good idea to have as a goal pure functions whenever possible. The proposed getRandomFileName2 is unlikely to be pure when composed with a 'real' random value generator, so a more functional design is warranted.
Anything that contains random (or Date or stuff like that). Will be considered impure and hard to test because what it returns doesn't strictly depends on its inputs (always different). However, if the random part of the function is injected, the function can be made "pure" in the test suite by replacing whatever injected randomness with something predictable.
function getRandomFileName(fileExtension = "", randomLetterFunc = getRandomLetter) {}
can be tested by calling it with a predictable "getLetter" function instead of a random one:
getRandomFileName("", predictableLetterFunc)
I am trying to write unit tests for a mobile app that has been developed in Appcelerator titanium. I am trying to unit test it with TiUnit and Jasmine.
One of my methods uses String.format(). How do I unit test that method since String.format() is not defined in Javascript?
function MyMethod(_flag, _myProperty, _propertyValue) {
if(_flag) {
_myProperty = String.format('The value :', _propertyValue);
}
}
Is it possible to mock this? Or can I add format() to the prototype of jasmine's String so that whenever it encounters format() in .js to be tested, it executes the format() which I will define in the test suite?
A way to get around this problem is to make this a pure function.
Take this small change as an example:
function MyMethod(_flag, _myProperty, _propertyValue, formatFunction) {
if(_flag) {
_myProperty = formatFunction('The value :', _propertyValue);
}
}
Now MyMethod does not have a dependency on anything external to the function. This allows you to use whatever string formatter you want, and in your case a mocked one.
In your test, you now have the ability to do something like this:
it('should format the string', () => {
const mockFormatter = () => {/*do the mock operation of your choosing here*/}
const formattedString = MyMethod(yourFlag, yourProperty, yourPropertyValue, mockFormatter)
assert(formattedString, expectedOutput)
})
What this allows is for you to not have to manipulate the global String object/prototypes, which can have implications elsewhere. Instead, you create a function that is agnostic to the formatter and are able to easily mock it.
Lastly, now that I have hopefully helped provide a path forward on your original question, I'm curious why you are after mocking the formatter? This seems like something you would always want to validate, and would have no harm in doing so. To me, and this can lead to very in depth and often pedantic discussions on testing, this already suffices as a unit test. It is not "pure", but as far as side-effects go, there are none and you are testing some basic expectations around data manipulation without.
I think mocking String.format() introduces unnecessary complexity to the test without any real gain in code-confidence.
**Edit: I assumed String.format() was a JS function I had not heard of, but that does not appear to be the case.
To achieve what you are after, and avoid the need to mock entirely, I think you should use string interpolation via string literals, or concatenation.
See here:
function MyMethod(_flag, _myProperty, _propertyValue) {
if(_flag) {
_myProperty = `The value : ${_propertyValue}`; // option 1 uses interpolation
// _myProperty = 'The value : ' + _propertyValue; // option 2 uses concatenation
}
}
Let's say I have a class component that has something like this:
export class Math extends React.Component {
...
someComponentMethod = numb => {
const sample = numb * 10
...
const result = numb -5
return result
}
Is it possible to make test assertions on sample variable in Jest?
It is not possible to write assertions for the private internals of functions.
I've personally found this barrier to encourage better tests to be written. By testing only the public API for correctness, you have the ability to refactor internals without having to update any tests. The existing tests continue to enforce that internal changes work correctly.
Writing tests against internal behavior easily increases the maintenance effort of the code being tested. Since the tests become more tightly coupled to the source code, they'll need more attention when making changes. This can also degrade the reliability of the tests, since more changes to the tests increases the likelihood of bugs manifesting in the tests themselves.
If you find yourself wanting to test some internal behavior, it might be a good time to extract some functionality. In your example, the sample value calculation could be extracted into a pure function of its own:
export class Math extends React.Component {
...
computeSampleValue(input) {
return input * 10
}
someComponentMethod = numb => {
const sample = this.computeSampleValue(numb)
...
const result = numb -5
return result
}
}
You can now assert that whatever logic is being used to calculate the sample value works as expected for various inputs. This extraction of logic often makes someComponentMethod more readable as well.
If you absolutely need to test some other internal behavior and are aware of the increased code debt, you can have your method perform side effects and write assertions for those. For example, instead of defining sample as a function-scope variable, create a this.sample property on the component instance and update that. In a test you then call the target method, and afterwards assert that componentInstance.sample was changed as expected.
I've managed to test a certain variable value inside a function the following way:
sum1.js
function sum() {
result = 1 + 2;
};
module.exports = sum;
sum1.test.js
const sum = require('./sum1');
sum();
test('adds 1 + 2 to equal 3', () => {
expect(result).toBe(3);
});
Hope it helps, cheers!
I'm wondering what the best practice is regarding using declared constants in JavaScript. Is it better to pass the constant as an argument to the function or is it better to use the constant without passing?
My instinct is to not pass the constant as an argument because that produces an unnecessary local copy of the variable. However, it might be more clear where the constant is coming from if it is passed.
const myConstant = 1;
myFunc();
myOtherFunc(myConstant);
/* use constant without passing */
function myFunc() {
console.log(`${myConstant} is a constant`);
}
/* pass constant as argument */
function myOtherFunc(localCopy) {
console.log(`${localCopy} is a constant`);
}
There are tradeoffs going in both directions, though most of them are in the area of unit testing and re-usability.
The more you hard code things, the less flexibility you have in testing.
Let me give what a contrived example:
const FIRST_NAME_MAX_LEN = 20;
And, in our validation code, we look at that constant and compare it to the length of the input field...
function validateFirstName() {
return document.getElementsByName("first-name")[0].length <= FIRST_NAME_MAX_LEN;
}
Ok, this works, but we have no way to test that validateFirstName() works without invoking the entire DOM. it is harder to test.
On the other hand, if we create a function like:
function validateStringLength(s, maxLength) {
return s.length <= maxLength;
}
then we've created a function that takes passed parameters, is re-usable in other places and very easily tested in any testing framework. DOM not required.
By relying upon the constant, you have created a dependency on that value and where it live. Research JavaScript Dependency Injection for much more on this topic.
Is it possible to test myInnerFunction below?
var val = function() {
var myInnerfunction = function(input) {
return input + ' I ADDED THIS';
};
return myInnerfunction('test value');
}();
Because myInnerFunction is essentially a private member of the anonymously executed outer function, it doesn't seem like it is testable from the outside.
You could intentionally expose a testing hook to the outside world, like possibly this:
var val = function() {
var myInnerfunction = function(input) {
return input + ' I ADDED THIS';
};
/* START test hook */
arguments.callee.__test_inner = myInnerFunction;
/* END test hook */
return myInnerfunction('test value');
}();
now, once val has been run at least once, you can reference val.__test_inner and call it with testable inputs.
The benefits to this approach:
1. you choose what is exposed and not (also a negative 'cause you have to REMEMBER to do so)
2. all you get is a copy-reference to the private method, so you can't accidentally change it, only use it and see what it produces
The drawbacks:
1. if the private member changes (or relies on) state of its host/parent function, it's harder for you to unit test around that, since you have to recreate or artificially control the host/parent state at the same time
2. As mentioned, these hooks have to be manually added
If you got really clever, you could have your build process look for blocks of comments like the above and remove the test hooks when creating your production build.
afaik unit testing does not concern about internal workings of things you test. The point is that you test the functionality ie: it does what it's supposed to do, not how it does it.
So if it uses an internal private member, it should not be testable...
You can test the external behavior that is observable. In this simple case you returned just the value of the inner function, but in a real world example you might combine the result of that inner function with something else. That combination is what you would test, not the direct outputs of the private method.
Trying to test the private method will make your code difficult to change and refactor, even when the external behavior is preserved. That said, I like to view unit tests not as extensive tests of your code, but simply providing an example of the API and how it behaves to different conditions. ;)
I think my answer for this is (like so many things) that I'm doing it wrong. What I've defined as a 'private' function is really something that needs to be tested. It was only private because I didn't want to expose it within a utilities api or something like that. But it could still be exposed through my application namespace.
So within the anonymous function that is executed on-dom-ready, I just attach my pre-defined functions as event handlers to the proper DOM hooks. The functions themselves, while not stored with my more open utilities functions, are still stored publicly within a package in my namespace associated with the DOM structure they are dealing with. This way I can get at them and test them appropriately.