简体   繁体   中英

How can I stub a problematic piece of code [Unit Testing]

New to writing unit tests and the concept of 'mocking' to be more exact. I have a basic function 'addPercentSign' that adds a percent character to a user input if it is between 50-100:

    addPercentSign: function (oEvent, control) {
        var inputVal = oEvent.getParameters().value;
        var inputNumber = parseFloat(inputVal);

        if (inputNumber) {

            if (inputNumber < 50 || inputNumber > 100) {
                return null;
            } else {
                var finalVal = inputNumber.toFixed(1);
                var finalOutput = finalVal + "%";

//Error: cannot setValue of undefined. How can I 'stub' the line below?
                control.learningCurve.setValue(finalOutput);

                return finalOutput;
            };
        }
    }

The Problem

The problem I'm facing is when I write a unit test for this function, I cannot test the returned value(finalOutput) because the line above it returns an error as it relies on the DOM element (control.learningCurve) to set a value. Since this is a unit test, I must isolate this function from any dependencies.

Therefore, I need to 'mock' the 'setValue' call. I figured creating a stub would make sense, but I'm not sure how?

Here is the unit test code that I'd like to test the above function (addPercentSign):

function (formatter, viewControls) {
    "use strict";

    var testEvent = {
        getParameters : function() {
                return {value : 50}
        }
    }

    QUnit.module("Formatter Functions");
    QUnit.test("Add Percent Sign", function (assert) {

    assert.ok(formatter.addPercentSign(testEvent, viewControls) == '50.0%', "Percent Sign Added: Pass");

    });
}

The Question

How can I mock the setter so I can unit test this function without DOM dependencies?:

control.learningCurve.setValue(finalOutput)

Sinon can be used as the test double.

This example is using sinon stub.

sinon.stub(control.learningCurve, 'setValue').returns('value that you need');

Edit:

function (formatter, viewControls) {
"use strict";

    sinon.stub(control.learningCurve, 'setValue').returns('value that you need');

    var testEvent = {
        getParameters : function() {
                return {value : 50}
        }
    }

    QUnit.module("Formatter Functions");
    QUnit.test("Add Percent Sign", function (assert) {

    assert.ok(formatter.addPercentSign(testEvent, viewControls) == '50.0%', "Percent Sign Added: Pass");

    });
}

I'm not sure as I am not a JS Ninja but I think it shouldn't be so hard.

Method you want to use is inside an object with name 'learningCurve' that's inside 'control' object.

If control is inside your formatter, can't you just do this:

formatter.control = {};
formatter.control.learningCurve = {};
formatter.control.learningCurve.setValue = function() {
    return something_to_return;
}   

assert.ok(formatter.addPercentSign(testEvent, viewControls) == '50.0%', "Percent Sign Added: Pass");

If it's not inside formatter than do that by creating a new instance of control and replacing what's inside like above.

I find one of the main added value of unit testing is that it makes you realize where your code could be refactored. In your case, there are 2 distinct concerns: Appending the % and modifying the DOM. By refactoring those 2 concerns into their individual functions, you can unit test your logic without mocking anything.

//Formerly addPercentSign
inputChanged: function (oEvent, control) {
    var inputVal = oEvent.getParameters().value;
    var inputNumber = parseFloat(inputVal);
    var formattedNumber = addPercentSign(inputNumber);
    control.learningCurve.setValue(formattedNumber);
}

function addPercentSign(inputNumber) {
    if (inputNumber < 50 || inputNumber > 100) {
        return inputNumber;
    }
    var finalVal = inputNumber.toFixed(1);
    return finalVal + "%";
}

Now you can test addPercentSign easily. You could unit test inputChanged as well, but that would just be unit testing the javascript framework.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM