【记录】记一次关于前端单元测试的全英文问卷调查( Survey: Automatically Generated Test Suites for JavaScript)

news2024/11/29 4:46:22

文章目录

  • OPENING STATEMENT
  • Background
  • Task background: Fix the failing test cases
    • Before the task:
  • Task: Fix the failing test cases
  • Task: Executable Documentation
    • Before the task:
  • Bonus Opportunity: One more task
  • Task: Test Cases Clustering
  • Reward
  • Thank You!


  • 原地址:Survey: Automatically Generated Test Suites for JavaScript

OPENING STATEMENT

You are being invited to participate in a research study that explores the effort developers put into understanding the content of the automatically generated test suite.

The purpose of this research study is to explore if different kinds of automatically generated test suites affect developers’ performance on program comprehension tasks. This study will take you approximately 30 minutes to complete. The anonymised data will be used for a master’s thesis project. We will be asking you to read multiple test suites, and answer related questions.

As with any online activity, the risk of a breach is always possible. To the best of our ability, your answers in this study will remain confidential. We will minimize any risks.

  • Until the end of the survey, the data is stored in Alchemer EU Data Center. Alchemer protects the respondents’ data and allows for its complete deletion. After the survey, the data is going to be deleted from Alchemer servers and transferred to an internal server at the Delft University of Technology. This means all data is protected by strict privacy laws. All the data are used for research purposes only; the data will not be, in any circumstances, sold or shared to third parties.
  • The only directly identifiable PPI (Personally Identifiable Information) that will be collected in this survey is the email address you provide at the end of the survey. The purpose of collecting the email address is for reward distribution, and all email addresses will be deleted once the project is completed. The email address data will only be accessible to the research team.
  • Only anonymised or aggregated information (questionnaire responses) will be made publicly available as part of the thesis project. All data will be uploaded to 4TU.ResearchData with public access for the purpose of FAIR (Findable, Accessible, Interoperable, Re-usable).

Your participation in this study is entirely voluntary and you can withdraw at any time. The email address data will be immediately deleted after the project ends, and the anonymous survey responses will be uploaded to 4TU.ResearchData with public access.

If you have any questions, please contact L.Lin-11@student.tudelft.nl. If you agree to this opening statement, you could participate in this study by clicking the button below and moving to the next page. Remember, your participation is completely voluntary, and you’re free to withdraw from the study at any time.

Thank you for considering participating in this research study.


  1. Select your Answer Choices *
    I consent to take part in this survey.
    I do not want to take part in this survey.

Next


Background

  1. What is your professional role? *(-- Please Select --)
  • Student (Bachelor or Master)
  • Researcher (Ph.D candidate, Post-doctoral, or Professor)
  • Software Developer
  1. Years of experience *
    < 1 year 1-2 years 3-6 years 6-10 years > 10 years
    Software testing
    JavaScript
Space Cell< 1 year1-2 years3-6 years6-10 years> 10 years
Software testing
JavaScript
对应图:

  1. Have you ever used any automated test case generation tool? (If the answer is yes, please list the name of the tools) *
  • Yes
  • No

Task background: Fix the failing test cases

  1. Suppose you are a software developer on a challenging project with a vast and complex codebase. This project has an elaborate, automatically generated test suite, including many regression tests. These tests, designed to ensure that changes don’t break existing functionality, are vital to the project. Your task is to implement a new feature, which involves modifying some of the underlying logic in the codebase.

在这里插入图片描述

  1. Following the project’s coding standards and best practices, you design and implement this change carefully. After finishing, you run the entire test suite. Your goal is to ensure that your changes haven’t inadvertently broken anything. Most of the tests pass. However, you find that some tests are failing.

Designers created these tests to check the behavior of the system’s part you’ve just modified. You changed this behavior intentionally to implement the new feature, so you know that the source code isn’t the issue. The problem is with the test suite—it hasn’t been updated to reflect the new expected behavior of the system.

在这里插入图片描述

  1. Instead of altering your source code to fit the old tests, which would mean failing to deliver the new feature, you meticulously examine the failing regression tests. You identify the assumptions these tests made about the system behavior that aren’t true anymore. Then, you fix these failing tests so that they accurately test the new behavior of the system.

Before the task:

We value your participation in this study and hope to gather the most accurate data possible to enhance the quality of our research. As part of this survey, we are recording the time you spend on each task.

We kindly request that once you start a task, you continue working on it without interruption until it’s completed. This measure will ensure the timing data we collect reflects the time actively spent on the task.

Please understand, this is not a test of speed, but a means for us to better understand the time dynamics of the tasks involved in our study.

We appreciate your understanding and cooperation. Thank you for your time and effort.


Task: Fix the failing test cases

As described in the previous page’s introduction, the bugs in this test code are caused by changes in the internal logic of certain methods in the class under test. The following image is a screenshot of the change history of the class under test. You can find the changes history here. These code changes resulted in the failure of some test cases in the test suite.

Your task is to find bugs in the test suite and answer questions.

You can find the class under test here.

在这里插入图片描述

  • Polygon.js
/**
 * Class representing a Polygon.
 */
export default class Polygon {
  /**
   * Create a polygon.
   */
  constructor() {
    this.vertices = [];
  }

  /**
   * Add a vertex to the polygon.
   * @param {Object} vertex - The vertex to add.
   * @throws {Error} If the vertex is not an object with numeric x and y properties.
   */
  addVertex(vertex) {
    if (typeof vertex.x !== "number" || typeof vertex.y !== "number") {
      throw new Error(
        "Vertex must be an object with numeric x and y properties"
      );
    }

    this.vertices.push(vertex);
  }

  /**
   * Remove a vertex from the polygon by its index.
   * @param {number} index - The index of the vertex to remove.
   * @throws {Error} If the index is out of bounds.
   */
  removeVertex(index) {
    if (index < 0 || index >= this.vertices.length) {
      throw new Error("Index out of bounds");
    }

    this.vertices.splice(index, 1);
  }

  /**
   * Calculate the perimeter of the polygon.
   * @returns {number} The calculated perimeter.
   */
  calculatePerimeter() {
    let perimeter = 0;

    for (let i = 0; i < this.vertices.length; i++) {
      const v1 = this.vertices[i];
      const v2 = this.vertices[(i + 1) % this.vertices.length];

      const dx = v2.x - v1.x;
      const dy = v2.y - v1.y;

      perimeter += Math.sqrt(dx * dx + dy * dy);
    }

    return perimeter;
  }

  /**
   * Calculate the area of the polygon.
   * @returns {number} The calculated area.
   */
  calculateArea() {
    let area = 0;

    for (let i = 0; i < this.vertices.length; i++) {
      const v1 = this.vertices[i];
      const v2 = this.vertices[(i + 1) % this.vertices.length];

      area += v1.x * v2.y - v2.x * v1.y;
    }

    return Math.abs(area) / 2;
  }

  /**
   * Check if a point is inside the polygon.
   * @param {Object} point - The point to check.
   * @returns {boolean} True if the point is inside the polygon, false otherwise.
   */
  isPointInside(point) {
    // This is a simple implementation based on ray casting algorithm and it assumes that the polygon is simple and convex
    let inside = false;

    for (
      let i = 0, j = this.vertices.length - 1;
      i < this.vertices.length;
      j = i++
    ) {
      const xi = this.vertices[i].x,
        yi = this.vertices[i].y;
      const xj = this.vertices[j].x,
        yj = this.vertices[j].y;

      const intersect =
        yi > point.y !== yj > point.y &&
        point.x < ((xj - xi) * (point.y - yi)) / (yj - yi) + xi;

      if (intersect) inside = !inside;
    }

    return inside;
  }

  /**
   * Translate the polygon by a vector.
   * @param {Object} vector - The vector to translate the polygon.
   * @throws {Error} If the vector is not an object with numeric x and y properties.
   */
  translate(vector) {
    if (typeof vector.x !== "number" || typeof vector.y !== "number") {
      throw new Error(
        "Vector must be an object with numeric x and y properties"
      );
    }

    for (let vertex of this.vertices) {
      vertex.x += vector.x;
      vertex.y += vector.y;
    }
  }

  /**
   * Scale the polygon by a factor.
   * @param {number} factor - The scale factor.
   * @throws {Error} If the scale factor is not a number.
   */
  scale(factor) {
    if (typeof factor !== "number") {
      throw new Error("Scale factor must be a number");
    }

    for (let vertex of this.vertices) {
      vertex.x *= factor;
      vertex.y *= factor;
    }
  }

  /**
   * Rotate the polygon by an angle.
   * @param {number} angle - The rotation angle.
   * @throws {Error} If the rotation angle is not a number.
   */
  rotate(angle) {
    if (typeof angle !== "number") {
      throw new Error("Rotation angle must be a number");
    }

    const cos = Math.cos(angle);
    const sin = Math.sin(angle);

    for (let vertex of this.vertices) {
      const x = vertex.x * cos - vertex.y * sin;
      const y = vertex.x * sin + vertex.y * cos;

      vertex.x = x;
      vertex.y = y;
    }
  }
}

  • Polygon.test.js
import Polygon from "Polygon.js";
import chai from "chai";
import chaiAsPromised from "chai-as-promised";

chai.use(chaiAsPromised);
const expect = chai.expect;

describe("Polygon.js", () => {
  context("Tests for multiple actions return Polygon object", () => {
    it("calls rotate after addVertex and returns Polygon object", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: 128,
        y: -7,
      };

      await polygon.addVertex(vertex);
      const angle = 39;

      await polygon.rotate(angle);
      expect(JSON.parse(JSON.stringify(polygon))).to.deep.equal({
        vertices: [
          {
            x: 40.876863046060585,
            y: 121.49930891784368,
          },
        ],
      });
    });

    it("calls scale after addVertex and returns Polygon object", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: 113,
        y: -704,
      };

      await polygon.addVertex(vertex);
      const factor = 15;

      await polygon.scale(factor);
      expect(JSON.parse(JSON.stringify(polygon))).to.deep.equal({
        vertices: [
          {
            x: 1695,
            y: -10560,
          },
        ],
      });
    });

    it("calls rotate and returns Polygon object", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: -82,
        y: -356,
      };

      await polygon.addVertex(vertex);
      const angle = "tqp1-E";
      await polygon.rotate(angle);

      expect(JSON.parse(JSON.stringify(polygon))).to.deep.equal({
        vertices: [
          {
            x: null,
            y: null,
          },
        ],
      });
    });
  });

  context("Tests for error handling of addVertex and removeVertex", () => {
    it("throws an error with positive index", async () => {
      const polygon = new Polygon();
      const index = 254;

      try {
        await polygon.removeVertex(index);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("throws an error with array vertex.x ", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: ["Ln0qFysBnz1"],
        y: "RTurhxUamchFWW",
      };

      try {
        await polygon.addVertex(vertex);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("calls removeVertex after addVertex and returns Polygon object", async () => {
      const polygon = new Polygon();
      const vertex = {
        y: -9.058398620535518,
        x: -2.4308041085729872,
      };

      await polygon.addVertex(vertex);
      const index = 0;

      await polygon.removeVertex(index);
      expect(JSON.parse(JSON.stringify(polygon))).to.deep.equal({
        vertices: [],
      });
    });

    it("throws an error with string factor", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: 282,
        y: -46,
      };

      await polygon.addVertex(vertex);
      const factor = "Nn_ESQK";

      try {
        await polygon.scale(factor);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("throws an error with undefined vertex", async () => {
      const polygon = new Polygon();
      const vertex = undefined;

      try {
        await polygon.addVertex(vertex);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("throws an error with null vertex", async () => {
      const polygon = new Polygon();
      const vertex = null;

      try {
        await polygon.addVertex(vertex);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("throws an error with undefined point.y", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: 212,
        y: -72,
      };

      await polygon.addVertex(vertex);
      const point = undefined;

      try {
        await polygon.isPointInside(point);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });
  });

  context("Test for isPointInside", () => {
    it("calls isPointInside and returns false", async () => {
      const polygon = new Polygon();
      const point = {
        y: 90,
        x: 198,
      };
      const returnValue = await polygon.isPointInside(point);

      expect(returnValue).to.equal(false);
    });
  });

  context("Tests for translate with different arguments", () => {
    it("calls translate after addVertex and returns Polygon object", async () => {
      const polygon = new Polygon();
      const vertex = {
        x: -94,
        y: 82,
      };

      await polygon.addVertex(vertex);
      const vector = {
        x: 108,
        y: -168,
      };

      await polygon.translate(vector);
      expect(JSON.parse(JSON.stringify(polygon))).to.deep.equal({
        vertices: [
          {
            x: -202,
            y: 250,
          },
        ],
      });
    });

    it("throws an error with string vector.x", async () => {
      const polygon = new Polygon();
      const vector = {
        x: "zwxHQ",
        y: 916,
      };

      try {
        await polygon.translate(vector);
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("calls translate and returns Polygon object", async () => {
      const polygon = new Polygon();
      const vector = {
        x: -287,
        y: -47,
      };

      await polygon.translate(vector);
      expect(JSON.parse(JSON.stringify(polygon))).to.deep.equal({
        vertices: [],
      });
    });
  });

  context("Test for calculatePerimeter", () => {
    it("calls calculatePerimeter after addVertex and returns positive", async () => {
      const polygon = new Polygon();
      const vertex1 = {
        x: 125,
        y: -7,
      };

      await polygon.addVertex(vertex1);
      const returnValue = await polygon.calculatePerimeter();

      expect(returnValue).to.equal(0);
    });
  });

  context("Tests for calculateArea", () => {
    it("throws an error with vertices.length=2", async () => {
      const polygon = new Polygon();
      const vector1 = {
        x: 459,
        y: -387,
      };

      await polygon.addVertex(vector1);
      const vector2 = {
        x: 361,
        y: 23,
      };
      await polygon.addVertex(vector2);

      try {
        const returnValue = await polygon.calculateArea();
        expect.fail();
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });

    it("throws an error with vertices.length=1", async () => {
      const polygon = new Polygon();
      const vertex1 = {
        x: 23,
        y: 499,
      };

      await polygon.addVertex(vertex1);

      try {
        const returnValue = await polygon.calculateArea();
        expect.fail();
      } catch (e) {
        expect(e).to.be.an("error");
      }
    });
  });
});
  1. Please select the test cases that you believe will fail. (The number of the failing test cases is no more than 5) *
  • calls rotate after addVertex and returns Polygon object
  • calls scale after addVertex and returns Polygon object
  • calls rotate and returns Polygon object
  • throws an error with positive index
  • throws an error with array vertex.x
  • calls removeVertex after addVertex and returns Polygon object
  • throws an error with string factor
  • throws an error with undefined vertex
  • throws an error with null vertex
  • throws an error with undefined point.y
  • calls isPointInside and returns false
  • calls translate after addVertex and returns Polygon object
  • throws an error with string vector.x
  • calls translate and returns Polygon object
  • calls calculatePerimeter after addVertex and returns positive
  • throws an error with vertices.length=2
  • throws an error with vertices.length=1
  1. For the test cases that you believe would fail, please provide the line number(s) or range of lines that you suspect may contain a bug, and explain what the bug is.

test case name what the bug is
Bug1

Bug2

Bug3

Bug4

Bug5

Space Celltest case namewhat the bug is
Bug1
Bug2
Bug3
Bug4
Bug5

在这里插入图片描述

  1. During the process of identifying bugs in the test cases, which parts of the test suite do you think would be helpful to you? *
  • Test suite structure or layout
  • Test case description or purpose
  • Input data and conditions
  • Expected results (assertions)
  • Executed steps and actions in test case
  • Code highlight
  • Other reason *

Task: Executable Documentation

  1. Suppose you are a new developer who is dealing with legacy codebase, one of the main challenges you face is understanding the existing system, which can be complex and convoluted. To make matters worse, the original developers are no longer available to address queries, and the documentation provided is both poor and outdated.
    在这里插入图片描述

  2. Despite these obstacles, there is a silver lining: the system boasts a suite of automatically generated unit tests for the class you are currently investigating. Remarkably, all the test cases in the suite have passed successfully.
    在这里插入图片描述

  3. Recognizing the value of these automatically generated unit tests, your objective is to dive into the content of this test suite. Your aim is to extract meaningful insights regarding the intended behavior and expected functionality of the CUT (class under test). By analyzing the test suite, you hope to gain a clearer understanding of how the CUT is supposed to do and what the expected outcome is under various circumstances.
    在这里插入图片描述

Before the task:

We value your participation in this study and hope to gather the most accurate data possible to enhance the quality of our research. As part of this survey, we are recording the time you spend on each task.

We kindly request that once you start a task, you continue working on it without interruption until it’s completed. This measure will ensure the timing data we collect reflects the time actively spent on the task.

Please understand, this is not a test of speed, but a means for us to better understand the time dynamics of the tasks involved in our study.

We appreciate your understanding and cooperation. Thank you for your time and effort.


Task: Executable Documentation

In this task, you will first be asked to carefully read a test suite that we have prepared.

This test suite contains valuable information necessary to answer the subsequent questions. It is important to understand the contents thoroughly before moving forward as the questions are closely related to the provided material.

Here the the automatically generated test suite for the CUT.

describe("AnonymousClass", () => {
  it("throws an error when itemName is null", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = null;
    const quantity = 6;

    try {
      await anonymousInstance.removeItem(itemName, quantity);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("throws an error when discount is boolean", async () => {
    const anonymousInstance = new AnonymousClass();
    const discount = false;

    try {
      await anonymousInstance.applyDiscount(discount);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("throws an error when itemName is boolean and quantity is negative", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = false;
    const quantity = -4.463676586368846;

    try {
      await anonymousInstance.removeItem(itemName, quantity);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls getTotalPrice and returns 0", async () => {
    const anonymousInstance = new AnonymousClass();
    const returnValue = await anonymousInstance.getTotalPrice();

    expect(returnValue).to.equal(0);
  });

  it("calls getItem and returns undefined", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = "f7TRlPDk8rN_1QhwDGbjrD0RS";
    const returnValue = await anonymousInstance.getItem(itemName);

    expect(returnValue).to.equal(undefined);
  });

  it("throws an error when itemName is boolean", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = true;
    const quantity = 5;

    try {
      await anonymousInstance.removeItem(itemName, quantity);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("throws an error when itemName is function", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = () => {};

    try {
      const returnValue = await anonymousInstance.findItem(itemName);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("throws an error when itemName is positve, quantity is string, and price is string", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = 9;
    const quantity = " ";
    const price = "QAvFGJhRb7V89b";

    try {
      await anonymousInstance.addItem(itemName, quantity, price);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls getItems and returns empty array", async () => {
    const anonymousInstance = new AnonymousClass();
    const returnValue = await anonymousInstance.getItems();

    expect(JSON.parse(JSON.stringify(returnValue))).to.deep.equal([]);
  });

  it("throws an error when itemName is array", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = ["FLxn4T3hFmo_pdwa"];

    try {
      const returnValue = await anonymousInstance.getItem(itemName);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls getTotalPrice and returns 0", async () => {
    const anonymousInstance = new AnonymousClass();
    const returnValue = await anonymousInstance.getTotalPrice();

    expect(returnValue).to.equal(0);
  });

  it("calls clearCart and return an object", async () => {
    const anonymousInstance = new AnonymousClass();
    await anonymousInstance.clearCart();

    expect(JSON.parse(JSON.stringify(anonymousInstance))).to.deep.equal({
      items: [],
    });
  });

  it("throws an error when itemName is number", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = 2;
    const quantity = 1;
    const price = 3;

    try {
      await anonymousInstance.addItem(itemName, quantity, price);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("throws an error when quantity is string and price is negative", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = "kzExxpeYXazeWf9mt1jS-lYsz_VLg";
    const quantity = "3bBWPprqh6-UQhXbeB3JDd3ZjZlxM";
    const price = -9;

    try {
      await anonymousInstance.addItem(itemName, quantity, price);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls getItemCount after clearCart and returns 0", async () => {
    const anonymousInstance = new AnonymousClass();
    await anonymousInstance.clearCart();
    const returnValue = await anonymousInstance.getItemCount();

    expect(returnValue).to.equal(0);
  });

  it("throws an error when price is negative", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = "eyAo";
    const quantity = 3;
    const price = -5;

    try {
      const returnValue = await anonymousInstance.validateInput(
        itemName,
        quantity,
        price
      );
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls findItem after addItem and returns undefined", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName1 = "  ";
    const quantity = 8;
    const price = 3;

    await anonymousInstance.addItem(itemName1, quantity, price);
    const itemName2 = "wzjojDV1";
    const returnValue2 = await anonymousInstance.findItem(itemName2);

    expect(returnValue2).to.equal(undefined);
  });

  it("throws an error when existingItem is null", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = "1q_r-l5U";
    const quantity = 9;

    try {
      await anonymousInstance.removeItem(itemName, quantity);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls applyDiscount and returns an object", async () => {
    const anonymousInstance = new AnonymousClass();
    const discount = 0.8899157137301756;
    await anonymousInstance.applyDiscount(discount);

    expect(JSON.parse(JSON.stringify(anonymousInstance))).to.deep.equal({
      items: [],
    });
  });

  it("throws an error when itemName is boolean, quantity is negative, and price is string", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName = true;
    const quantity = -5;
    const price = "rLq8PuPerUGBxu-Eun0OqMbNU";

    try {
      await anonymousInstance.addItem(itemName, quantity, price);
    } catch (e) {
      expect(e).to.be.an("error");
    }
  });

  it("calls getItem after addItem and returns undefined", async () => {
    const anonymousInstance = new AnonymousClass();
    const itemName1 = "pvl3A6SYojiN3mtY-cRXQfm5!93";
    const quantity = 1;
    const price = 9.956023066500322;

    await anonymousInstance.addItem(itemName1, quantity, price);
    const itemName2 = "VNVsx7";
    const returnValue = await anonymousInstance.getItem(itemName2);

    expect(returnValue).to.equal(undefined);
  });
});
  1. Based on the functionalities demonstrated in the provided test cases, can you infer an approximate name for the AnonymousClass ?
    (A name that conveys the class’s general purpose or a specific class name that might be used in a real codebase) *

Class Name [ _______________________ ]

Based on your understanding from the test suite, can you identify any specific inputs or scenarios where the removeItem and addItem might throw an exception? Select the answer that you think is appropriate.


  1. removeItem *
  • Removing an item when the item name is null.
  • Removing an item with a quantity greater than the existing quantity in the cart.
  • Removing an item with a negative quantity.
  • Removing an item that does not exist in the shopping cart.
  • Removing an item when the quantity is a postive number.
  • Removing an item from an empty shopping cart.
  • Removing an item when the itemName is a number.

  1. addItem *
  • Adding an item when the item name is an empty string.
  • Adding an item when the quantity is not a positive number.
  • Adding an item when the price is a string value.
  • Adding an item when the item already exists in the shopping cart
  • Adding an item when the price is a floating point number.
  • Adding an item when the both price and quantity are positive numbers.

Here we provide the source code of the addItem and removeItem.

Please read the following code and answer the related questions.

addItem(itemName, quantity, price) {
  this.validateInput(itemName, quantity, price);

  const existingItem = this.findItem(itemName);

  if (existingItem) {
    existingItem.quantity += quantity;
  } else {
    this.items.push(new ShoppingCartItem(itemName, quantity, price));
  }

  return this;
}

removeItem(itemName, quantity) {
  this.validateInput(itemName, quantity, 0);

  const existingItem = this.findItem(itemName);

  if (!existingItem) {
    throw new Error("Item does not exist");
  }

  if (existingItem.quantity < quantity) {
    throw new Error("Invalid quantity");
  } else if (existingItem.quantity === quantity) {
    this.items = this.items.filter((item) => item.productName !== itemName);
  } else {
    existingItem.quantity -= quantity;
  }

  return this;
}

validateInput(itemName, quantity, price) {
  const errors = [];

  if (typeof itemName !== "string" || itemName.length === 0) {
    errors.push("Invalid item name");
  }
  if (typeof quantity !== "number" || quantity < 0) {
    errors.push("Invalid quantity");
  }
  if (typeof price !== "number" || price < 0) {
    errors.push("Invalid price");
  }

  if (errors.length > 0) {
    throw new Error(errors.join(", "));
  }
}

findItem(itemName) {
  if (typeof itemName !== "string" || itemName.length === 0) {
    throw new Error("Invalid item name");
  }
  return this.items.find((item) => item.productName === itemName);
}
  1. After reading the source code, you may have a complete understanding of the inputs, outputs, and operational logic of these two methods. Do you agree that *

the test suite provided earlier effectively serves as “live” documentation that helps you understand these two methods better.

  • Strongly disagree
  • Disagree
  • Neutral
  • Agree
  • Strongly agree
  • Not applicable

  1. Now, let’s expand the scope to the entire class under test. Do you agree that *

it was easy for you to understand the functionality and design of the AnonymousClass from the test suite

  • Strongly disagree
  • Disagree
  • Neutral
  • Agree
  • Strongly agree
  • Not applicable

you were confident in your understanding of the AnonymousClass based on the test suite

  • Strongly disagree
  • Disagree
  • Neutral
  • Agree
  • Strongly agree
  • Not applicable

  1. Did you encounter any difficulties while reading the test cases, or do you think some of the content in the test cases was helpful to you? *
    Selection: *
  • encounter some difficulties
  • the test suite is helpful

Please elaborate on your answer *


Bonus Opportunity: One more task

We value your insights and would like to offer you an optional opportunity to earn additional rewards. By choosing to complete one more task following, you will receive extra reward.

  1. Please indicate your interest:
  • I would like to participate and earn bonus.
  • I would like to skip this opportunity.

Task: Test Cases Clustering

In this task, we will provide you with a set of automatically generated test cases. Your task is to review these test cases and group them into different categories. This process is known as ‘test case clustering’.

You need to categorize these test cases based on your own idea, such as the functionality they test, the methods they use, the input data they require, or any other criteria that make sense to you. We encourage you to create clusters that help you understand the test suite and the underlying code better.

After you finish the clustering, we will ask you to provide a brief justification for your categorization. This is to help us understand your thought process and the logic behind your decisions.

Here are all the test cases you will use in this task, you can go to the question part first and review the code as you need.

Find the class under test here.

it("TC1: throws an error when itemName is null", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = null;
  const quantity = 6;

  try {
    await shoppingCart.removeItem(itemName, quantity);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC2: throws an error when discount is boolean", async () => {
  const shoppingCart = new ShoppingCart();
  const discount = false;

  try {
    await shoppingCart.applyDiscount(discount);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC3: throws an error when itemName is boolean and quantity is negative", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = false;
  const quantity = -4.463676586368846;

  try {
    await shoppingCart.removeItem(itemName, quantity);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC4: calls getTotalPrice and returns 0", async () => {
  const shoppingCart = new ShoppingCart();
  const returnValue = await shoppingCart.getTotalPrice();

  expect(returnValue).to.equal(0);
});

it("TC5: calls getItem and returns undefined", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = "f7TRlPDk8rN_1QhwDGbjrD0RS";
  const returnValue = await shoppingCart.getItem(itemName);

  expect(returnValue).to.equal(undefined);
});

it("TC6: throws an error when itemName is boolean", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = true;
  const quantity = 5;

  try {
    await shoppingCart.removeItem(itemName, quantity);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC7: throws an error when itemName is function", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = () => {};

  try {
    const returnValue = await shoppingCart.findItem(itemName);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC8: throws an error when itemName is positve, quantity is string, and price is string", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = 9;
  const quantity = " ";
  const price = "QAvFGJhRb7V89b";

  try {
    await shoppingCart.addItem(itemName, quantity, price);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC9: calls getItems and returns empty array", async () => {
  const shoppingCart = new ShoppingCart();
  const returnValue = await shoppingCart.getItems();

  expect(JSON.parse(JSON.stringify(returnValue))).to.deep.equal([]);
});

it("TC10: throws an error when itemName is array", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = ["FLxn4T3hFmo_pdwa"];

  try {
    const returnValue = await shoppingCart.getItem(itemName);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC11: calls getTotalPrice and returns 0", async () => {
  const shoppingCart = new ShoppingCart();
  const returnValue = await shoppingCart.getTotalPrice();

  expect(returnValue).to.equal(0);
});

it("TC12: calls clearCart and return an object", async () => {
  const shoppingCart = new ShoppingCart();
  await shoppingCart.clearCart();

  expect(JSON.parse(JSON.stringify(shoppingCart))).to.deep.equal({
    items: [],
  });
});

it("TC13: throws an error when itemName is number", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = 2;
  const quantity = 1;
  const price = 3;

  try {
    await shoppingCart.addItem(itemName, quantity, price);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC14: throws an error when quantity is string and price is negative", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = "kzExxpeYXazeWf9mt1jS-lYsz_VLg";
  const quantity = "3bBWPprqh6-UQhXbeB3JDd3ZjZlxM";
  const price = -9;

  try {
    await shoppingCart.addItem(itemName, quantity, price);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC15: calls getItemCount after clearCart and returns 0", async () => {
  const shoppingCart = new ShoppingCart();
  await shoppingCart.clearCart();
  const returnValue = await shoppingCart.getItemCount();

  expect(returnValue).to.equal(0);
});

it("TC16: throws an error when price is negative", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = "eyAo";
  const quantity = 3;
  const price = -5;

  try {
    const returnValue = await shoppingCart.validateInput(
      itemName,
      quantity,
      price
    );
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC17: calls findItem after addItem and returns undefined", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName1 = "  ";
  const quantity = 8;
  const price = 3;

  await shoppingCart.addItem(itemName1, quantity, price);
  const itemName2 = "wzjojDV1";
  const returnValue2 = await shoppingCart.findItem(itemName2);

  expect(returnValue2).to.equal(undefined);
});

it("TC18: throws an error when existingItem is null", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = "1q_r-l5U";
  const quantity = 9;

  try {
    await shoppingCart.removeItem(itemName, quantity);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC19: calls applyDiscount and returns an object", async () => {
  const shoppingCart = new ShoppingCart();
  const discount = 0.8899157137301756;
  await shoppingCart.applyDiscount(discount);

  expect(JSON.parse(JSON.stringify(shoppingCart))).to.deep.equal({
    items: [],
  });
});

it("TC20: throws an error when itemName is boolean, quantity is negative, and price is string", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName = true;
  const quantity = -5;
  const price = "rLq8PuPerUGBxu-Eun0OqMbNU";

  try {
    await shoppingCart.addItem(itemName, quantity, price);
  } catch (e) {
    expect(e).to.be.an("error");
  }
});

it("TC21: calls getItem after addItem and returns undefined", async () => {
  const shoppingCart = new ShoppingCart();
  const itemName1 = "pvl3A6SYojiN3mtY-cRXQfm5!93";
  const quantity = 1;
  const price = 9.956023066500322;

  await shoppingCart.addItem(itemName1, quantity, price);
  const itemName2 = "VNVsx7";
  const returnValue = await shoppingCart.getItem(itemName2);

  expect(returnValue).to.equal(undefined);
});
  1. Please classify/cluster/group the test cases into any number of categories based on any rules you desire.

Please remember, there are no ‘right’ or ‘wrong’ answers in this task. We are interested in your personal approach to understanding test cases and how you perceive their organization can aid in comprehension.

(tip: you can review the categoried image by zooming in or out on the webpage, the image retains its original resolution) *
Drag items from below into the appropriate categories.
[____________________]

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

Drop an item here to create a new category
[____________________]
16. Please provide a simple explanation of your rules of categorizing. *

Reward

  1. Please write down your email for rewarding. If you do not receive your reward in 3 working days, please send a email to me (L.Lin-11@student.tudelft.nl) *

Thank You!

Thank you for taking our survey. Your response is very important to us.


测试需要分为基础测试和功能测试,基础测试保证程序运行下去,功能测试保证程序结果是理想的


摘录自一次问卷调查,为防原地址失效特记录于此,英文好的小伙伴可以过一遍,相信对前端单元测试的理解会有所帮助


over。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1448038.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RocketMQ与Kafka架构深度对比

在分布式系统中&#xff0c;消息中间件扮演着至关重要的角色&#xff0c;它们负责在系统组件之间传递消息&#xff0c;实现解耦、异步通信和流量削峰等功能。RocketMQ与Kafka作为两款流行的消息中间件&#xff0c;各自拥有独特的架构设计和功能特性。本文将深入对比分析RocketM…

【机器学习300问】22、什么是超参数优化?常见超参数优化方法有哪些?

在之前的文章中&#xff0c;我主要介绍了学习率 η和正则化强度 λ 这两个超参数。这篇文章中我就主要拿这两个超参数来进行举例说明。如果想在开始阅读本文之前了解这两个超参数的有关内容可以参考我之前的文章&#xff0c;文章链接为你放在了这里&#xff1a; 【机器学习300…

算法沉淀——哈希算法(leetcode真题剖析)

算法沉淀——哈希算法 01.两数之和02.判定是否互为字符重排03.存在重复元素04.存在重复元素 II05.字母异位词分组 哈希算法&#xff08;Hash Algorithm&#xff09;是一种将任意长度的输入&#xff08;也称为消息&#xff09;映射为固定长度的输出的算法。这个输出通常称为哈希…

2024.2.8

1. 现有文件test.c\test1.c\main.c,编写Makkefile Makefile&#xff1a; CCgcc EXEa.out OBJS$(patsubst %.c,%.o,$(wildcard *.c)) CFLAGS-c -oall:$(EXE)$(EXE):$(OBJS)$(CC) $^ -o $%.o:%.c$(CC) $(CFLAGS) $ $^.PHONY:cleanclean:rm $(OBJS) $(EXE) 2. C编程实现&#x…

HarmonyOS鸿蒙学习基础篇 - Column/Row 组件

前言 Row和Column组件是线性布局容器&#xff0c;用于按照垂直或水平方向排列子组件。Row表示沿水平方向布局的容器&#xff0c;而Column表示沿垂直方向布局的容器。这些容器具有许多属性和方法&#xff0c;可以方便地管理子组件的位置、大小、间距和对齐方式。例如&#xff0c…

netstat命令

netstat 是一个计算机网络命令行工具&#xff0c;用于显示网络连接、路由表和网络接口等网络相关信息。netstat 命令可以在各种操作系统上使用&#xff0c;包括 Windows、Linux 和 macOS 等。 在使用 netstat 命令时&#xff0c;可以提供不同的选项来显示不同类型的网络信息。…

【北邮鲁鹏老师计算机视觉课程笔记】08 texture 纹理表示

【北邮鲁鹏老师计算机视觉课程笔记】08 texture 纹理表示 1 纹理 规则和不规则的 2 纹理的用处 从纹理中恢复形状 3 分割与合成 4 分析纹理进行分类 通过识别纹理分析物理性质 如何区分纹理 5 寻找有效的纹理分类方法 发现模式、描述区域内模式 A对应图2 B对应图…

Linux命令行全景指南:从入门到实践,掌握命令行的力量

目录 知识梳理思维导图&#xff1a; linux命令入门 为什么要学Linux命令 什么是终端 什么是命令 关于Linux命令的语法 tab键补全 关于命令提示符 特殊目录 常见重要目录 /opt /home /root /etc /var/log/ man命令 shutdown命令 history命令 which命令 bash…

单链表的介绍

一.单链表的概念及结构 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表 中的指针链接次序实现的 。 结构&#xff1a;根据个人理解&#xff0c;链表的结构就像火车厢一样&#xff0c;一节一节连在一起的&#x…

ClickHouse--07--SQL DDL 操作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 SQL DDL 操作1 创建库2 查看数据库3 删除库4 创建表5 查看表6 查看表的定义7 查看表的字段8 删除表9 修改表9.1 添加列9.2 删除列9.3 清空列9.4 给列修改注释9.5 修…

深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之倒排索引(三)

当我们谈论Elasticsearch&#xff08;简称ES&#xff09;时&#xff0c;我们经常会提到它的高效搜索能力。而这背后的核心技术之一就是倒排索引。那么&#xff0c;什么是倒排索引&#xff0c;以及它是如何在Elasticsearch中工作的呢&#xff1f; 深入解析Elasticsearch的内部数…

机器学习系列——(二十一)神经网络

引言 在当今数字化时代&#xff0c;机器学习技术正日益成为各行各业的核心。而在机器学习领域中&#xff0c;神经网络是一种备受瞩目的模型&#xff0c;因其出色的性能和广泛的应用而备受关注。本文将深入介绍神经网络&#xff0c;探讨其原理、结构以及应用。 一、简介 神经网…

PHP脉聊交友系统网站源码,可通过广告变现社交在线聊天交友即时通讯APP源码,附带视频搭建教程

探索全新社交体验&#xff1a;一站式PHP交友网站解决方案 &#x1f310; 全球化交友&#xff0c;无界沟通 在数字化的浪潮下&#xff0c;社交已不再受地域限制。我们的PHP交友网站不仅支持多国语言&#xff0c;还配备了即时翻译功能&#xff0c;让您轻松跨越语言障碍&#xff…

分享87个CSS3特效,总有一款适合您

分享87个CSS3特效&#xff0c;总有一款适合您 87个CSS3特效下载链接&#xff1a;https://pan.baidu.com/s/1CAxe8nPBzXvH7Nr6B_U72Q?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不…

MySQL基本操作之数据库的操作

一.创建数据库 1.基本语法 create database 数据库名&#xff1b; 注意别忘记加分号。 2.if not exists 数据库名字是唯一的&#xff0c;所以不可以创建已存在的数据库&#xff0c;如下&#xff1a; 重复创建就会报错 所以有了if not exists这个语法&#xff0c;加上之后&…

片上网络NoC(5)——非直连拓扑

目录 一、前言 二、概念阐述 三、交叉开关 四、蝶形网络 五、clos网络 六、fat tree网络 6.1 clos网络的折叠过程 七、总结 一、前言 本文继续介绍片上网络的拓扑&#xff0c;在之前的文章中&#xff0c;我们已经介绍了片上网络的拓扑指标和直连拓扑的相关内容&#xf…

正月初五迎财神

大家好&#xff0c;我是小悟 正月初五&#xff0c;人们在这一天迎接财神&#xff0c;祈求财运亨通、事业顺利。按照习俗&#xff0c;家家户户都会燃放鞭炮、点灯笼、摆设祭品&#xff0c;以示虔诚。 早晨&#xff0c;太阳刚刚升起&#xff0c;大家便早早起床&#xff0c;开始准…

软件架构与系统架构:区别与联系的分析

软件架构与系统架构&#xff1a;区别与联系的分析 在信息技术领域&#xff0c;软件架构和系统架构这两个术语经常被提及。尽管它们在某些方面有重叠&#xff0c;但它们确实代表了不同的概念和聚焦点。理解这两种架构之间的区别和联系对于任何从事技术开发和设计的专业人士都是至…

【Python网络编程之TCP三次握手】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python开发技术 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; Python网络编程之[TCP三次握手] 代码见资源&#xff0c;效果图如下一、实验要求二、协议原理2.…

DS Wannabe之5-AM Project: DS 30day int prep day15

Q1. What is Autoencoder? 自编码器是什么&#xff1f; 自编码器是一种特殊类型的神经网络&#xff0c;它通过无监督学习尝试复现其输入数据。它通常包含两部分&#xff1a;编码器和解码器。编码器压缩输入数据成为一个低维度的中间表示&#xff0c;解码器则从这个中间表示重…