Examining a feature by solely utilizing stubs

I've been immersed in writing tests for the past few weeks. In my workplace, we utilize Mocha as our test runner and Chai for assertions, with Sinon for creating stubs. However, there's a recurring issue that's been bothering me. I've written tests for several functions where I stub out every dependency without considering the arguments passed to the function being tested. Let me illustrate with an example:

module.exports = {
  "someFunc": (arg1, arg2) => {
    return new Promise((resolve, reject) => {
      Promise.all(arg1).then(data => {
        let someArray = ourHelperLib.toArray(data);
        let someObj = ourHelperLib.toObject(arg2);
          if(someArray.length == 0){
            reject("error");
          }else{
            resolve({
              "array": someArray,
              "object": someObj
            });
          }
        }).catch(err => {
            reject(err);
        });
    });
  },
}
  1. When testing this function, I've created a scenario where I stub Promise.all() to throw an error.
  2. In another test, I stub Promise.all() to return false and ourHelperLib.toArray() to throw an error, checking how the function handles it.
  3. For a third test, I stub all three: Promise.all(), ourHelperLib.toArray(), and ourHelperLib.toObject() to return false values and assess the output for a resolved promise after completing the operations.

It's evident from the function definition that the arguments are directly passed to the stubbed dependencies, leading me to overlook these values completely, like this:

const stubOurHelperLibToThrowError = argFromCaller => {
    throw new Error("This is an error");
}

By neglecting the argument handling within my stub functions, I realize I'm not effectively testing the input data of the function. Instead, I focus solely on validating the logic structure of someFunc().

Is this approach considered best practice? Seeking clarity on this topic as I aim to establish comprehensive guidelines for unit testing at my current workplace.

Peace!

Answer №1

You have the option to hand off promises to your function without needing to simulate anything for most of the scenarios you are discussing.


I encountered a situation where I faked Promise.all() to throw an error

Instead of faking Promise.all, simply provide an array with a rejected Promise to your function:

someFunc([Promise.reject(new Error('fail'))], null)

This will make the Promise.all go into the catch block and reject with the error.


I simulated Promise.all() to return a false positive result and stimulate ourHelperLib.toArray() to throw an error, then test if the function handles it correctly or not

Once again, rather than simulating Promise.all, pass an array with a resolved Promise:

someFunc([Promise.resolve('a value')], null)

You can either stimulate ourHelperLib.toArray to produce an error or resolve your Promise array to something that triggers ourHelperLib.toArray to throw.


For my third test, I faked Promise.all(), ourHelperLib.toArray(), and ourHelperLib.toObject() to return false positive results and then checked the output for a resolved promise containing the result after operations.

Faking ourHelperLib.toArray and ourHelperLib.toObject is optional. Unless they are resource-intensive (e.g., making network requests), it's usually better to call them normally.

You can feed the data intended for

ourHelperLib.toArray</code in the array of resolved <code>Promise
s and simply provide the value for ourHelperLib.toObject as the second argument:

someFunc([
  Promise.resolve('value 1 for ourHelperLib.toArray'),
  Promise.resolve('value 2 for ourHelperLib.toArray')
], 'value for ourHelperLib.toObject')

...and confirm that the resulting Promise resolves to the expected value.


In general, it is recommended to follow black box testing principles.

This function seems to have no side effects and merely returns a Promise that resolves to a result based on the input parameters.

Unless the function relies on resource-heavy dependencies, it is advisable to test a function like this by providing inputs and checking the outcome.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Triggering an event upon completion of ng-repeat's execution

I am facing a challenge in updating the style of a specific element after ng-repeat has finished changing the DOM. The directive I have implemented for triggering ng-repeat works perfectly fine when adding items to the model, but it does not get called whe ...

What is the best method for adjusting the text size within a doughnut chart using react-chartjs-2?

Is there a way to adjust the text size within the doughnut chart using react-chartjs-2? I find that the center text appears too small. https://i.stack.imgur.com/QsI0V.png import React, {Fragment} from 'react'; import Chart from 'chart.js&a ...

Ways to sort out chosen checkboxes in angularJS

Displayed all the objects in an array as a list using ng-repeat, with a checkbox for each value. My goal is to filter the checkboxes and create a new JSON when clicking Apply Filter based on checked/unchecked values. Current Approach I attempted to stor ...

Unable to trigger JQuery .blur event

I am currently working on implementing server-side validation for an input field that needs to be validated when it loses focus. However, I'm running into an issue where the alert is not triggered when the input field loses focus. Here's a snipp ...

Insert information into an array within a mongoDB structure using the Mongoose library

Is it possible to add elements into an array in a mongoDB schema? For instance, in the given schema: var ProviderSchema = new Schema({ keyWords: [String] }); How can I insert data into the keyWords field using the specified route: app.put(&a ...

Storing sound recordings with GridFS

I am currently facing an issue with the following code, it is only working partially and I require assistance in fixing it. The function saveAudioToGridFS() should return a file ID to its calling function. Despite verifying that the value to be returned ...

Json data integrated dropdown menu

I have successfully retrieved data from a Json array and displayed it in a dropdown list. However, I am facing an issue where I want to only show the name of the city instead of both the name and description. If I remove cities[i]['description'], ...

Struggling to implement the UI router into my Angular Framework

I've been working on a framework that is supposed to be router agnostic. While I've managed to make it work with ngRoute, I just can't seem to get it functioning with UI Router. Here's a snippet of the main app module: (function () { ...

Choose the tag and class then retrieve the custom attribute

I'm currently attempting to retrieve a specialized attribute utilizing jquery and subsequently choose it, nevertheless I am encountering some difficulties with the process Below is the jquery code I have implemented to access the value var stockId = ...

What is the solution to the problem "How can you resolve the issue where 'Cannot set property 'ref' of undefined' occurs"?

My goal is quite simple - I just want to retrieve data from Cloud Firestore. Below is the code snippet I am using: import React from 'react'; import firebase from "react-native-firebase"; export default class newsFeed extends React.Component { ...

What exactly does Apple consider as a "user action"?

In the midst of my current web project, I am facing a challenge with initiating video playback after a swipe event. Despite utilizing the HTML5 video player and JavaScript to detect swipes, I have encountered difficulties in achieving this functionality. I ...

Exploring Angular 4: Iterating Over Observables to Fetch Data into a Fresh Array

Context Currently, I am in the process of developing a find feature for a chat application. In this setup, each set of messages is identified by an index. The goal of the `find()` function is to retrieve each message collection reference from the `message ...

Placing the jQuery/javascript source pages right before the closing body tag

Multiple plugin instructions recommend placing the javascript/jQuery source right before the closing body tag. I wondered why this advice is given, but couldn't find a clear explanation for it. In my experience, placing the src file anywhere in the s ...

Automatic line breaks in MathJax when displayed in a modal dialogue box

As part of a math project, I need to display the solution of a problem in a Sweetalert2 modal. However, despite using the following code: <script type="text/x-mathjax-config"> MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$ ...

Is there a way to trigger a function in an AngularJS controller from a Backbone controller?

I've been working on an application that was originally developed using backbone and jQuery, but we had to incorporate new modules built with angular to meet client requirements. Routing in the application is handled by backbone route, and we have suc ...

Obtain additional information to address concerns related to onZoom and onPan issues on the line

Attempting to enhance my Chart.js line chart by fetching more data or utilizing cached backup data during onZoom/onPan events has proven quite challenging. The original code base is too intricate to share entirely, but I will outline the approaches I have ...

Tips for creating AngularJS nested transcludes

I'm currently delving into the world of angular directives/transclusion to manage the creation of custom panels within my application. Unfortunately, I seem to have hit a roadblock as the transcluded content is not displaying in the HTML. Below is th ...

Identifying the user's location within the application and dynamically loading various Angular scripts

Currently, I am working on a large-scale web application using Laravel and Angular. In this project, I have integrated various angular modules that come with their own controllers, directives, and views. One challenge I am facing is the need to load diffe ...

Pressing the submit button will trigger the execution of a .php script, which will then generate a popup on the screen and refresh a specific part of

I have a select form and submit button on my page, which are dynamically generated based on entries in the database. Here is the HTML output: <div id="structures"> <h1>Build</h1> <form name="buildForm" id="buildForm" method="POST" ons ...

Implementing Pagination Functionality Using Knockout.js

Sample JSON Data [{ "name": "A Goofy Movie (1995) 720p HDTVRip x264 Eng Subs [Dual Audio] [Hindi DD 2.0 - English DD 2.0] Exclusive By -=!Dr.STAR!=-", "progress": 0, "size": "1.06 GB", "downloaded": "87.98 KB", "hash": "8fe65e43464debe ...