Author Archives: RickDjouwe1

The Intersection of Manual Testing, Automated Testing, Equivalence Class Testing, and Security Testing

Hello guys, welcome to my second blog. In my previous blog, I explored JUnit testing, focusing on boundary value analysis and how to use assert Throws for exception handling in Java. Those concepts helped us understand how to write robust test cases and ensure that our software behaves correctly at its limits.

Building on that foundation, this post expands into a broader discussion of manual vs. automated testing, equivalence class testing, and security testing. These methodologies work together to create a comprehensive testing strategy that ensures software is functional, efficient, and secure.

Introduction

Software testing is a critical part of the software development lifecycle (SDLC). Among the various testing methodologies, manual testing, automated testing, equivalence class testing, and security testing play vital roles in ensuring software reliability, performance, and security. This article explores these techniques, their strengths, and how they work together.

Manual vs. Automated Testing

Testing software can be broadly categorized into manual testing and automated testing. Each approach serves specific purposes and has its advantages.

Manual Testing

Manual testing involves human testers executing test cases without automation tools. It is useful for exploratory testing, usability testing, and cases requiring human judgment.

Pros:

  • Suitable for UI/UX testing and exploratory testing
  • Requires no programming skills
  • Provides a human perspective on software quality

Cons:

  • Time-consuming and repetitive
  • Prone to human errors
  • Inefficient for large-scale projects

Automated Testing

Automated testing uses scripts and testing frameworks to execute test cases automatically. It is ideal for regression testing and performance testing.

Pros:

  • Faster execution and scalable for large projects
  • Reduces human errors
  • Works well with continuous integration/continuous deployment (CI/CD)

Cons:

  • High initial setup cost
  • Requires programming expertise
  • Not suitable for exploratory testing

Example: Java Automated Test Using Selenium

Here is a basic example of using Java to automate a test: I have a simple Calculator class and an Add method. There is a test that runs without human intervention once executed

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

public class CalculatorTest {
    @Test
    public void testAddition() {
        Calculator calculator = new Calculator();
        int result = calculator.add(2, 3);
        assertEquals(5, result); 
    }
}

Equivalence Class Testing

Equivalence Class Testing (ECT) is a black-box testing technique that reduces the number of test cases while ensuring comprehensive test coverage. It divides input data into equivalence classes, where each class represents similar expected outcomes.

How It Works:

  • Identify input conditions
  • Categorize inputs into equivalence classes (valid and invalid)
  • Select one representative input from each class for testing

Example: Equivalence Class Testing in Java

Consider a function that validates age input:

public class AgeValidator {
    public static String validateAge(int age) {
        if (age >= 18 && age <= 60) {
            return "Valid Age";
        } else {
            return "Invalid Age";
        }
    }

    public static void main(String[] args) {
        System.out.println(validateAge(25)); // Valid input class
        System.out.println(validateAge(17)); // Invalid input class
        System.out.println(validateAge(61)); // Invalid input class
    }
}

Security Testing: A Critical Component

Security testing ensures that applications are protected against cyber threats. This is increasingly crucial with rising cyberattacks and data breaches.

Key Security Testing Techniques:

  • Penetration Testing: Simulating cyberattacks to identify vulnerabilities.
  • Static Code Analysis: Reviewing source code for potential security flaws.
  • Dynamic Analysis: Testing a running application for security weaknesses.
  • Fuzz Testing: Inputting random data to identify unexpected behavior.

Example: Basic SQL Injection Test

A common security vulnerability is SQL Injection. Here’s an example of a vulnerable and a secure implementation:

Vulnerable Code:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class SQLInjectionVulnerable {
    public static void getUserData(String userId) {
        try {
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
            Statement stmt = conn.createStatement();
            String query = "SELECT * FROM users WHERE id = " + userId; // Vulnerable to SQL Injection
            ResultSet rs = stmt.executeQuery(query);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Secure Code:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class SQLInjectionSecure {
    public static void getUserData(String userId) {
        try {
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
            String query = "SELECT * FROM users WHERE id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setString(1, userId);
            ResultSet rs = pstmt.executeQuery();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

How These Testing Methods Work Together

Each testing approach contributes uniquely to software quality:

  • Manual and automated testing ensure functional correctness and usability.
  • Equivalence class testing optimizes test case selection.
  • Security testing safeguards applications from threats.

By integrating these methods, development teams can achieve efficiency, reliability, and security in their software products.

Conclusion

A strong testing strategy incorporates manual testing, automated testing, equivalence class testing, and security testing. Leveraging these approaches ensures robust software quality while improving development efficiency.

For further exploration, consider:

From the blog Rick’s Software Journal by RickDjouwe1 and used with permission of the author. All other rights reserved by the author.

Effective Exception Testing in JUnit 5: Boundary Value Testing and AssertThrows

Introduction

In modern software development, ensuring that a program handles exceptions correctly is crucial for building robust applications. Exception testing in JUnit 5 allows developers to verify that their code properly handles error scenarios, improving reliability and maintainability. This blog post explores key techniques such as Testing for Exceptions in JUnit 5, Boundary Value Testing, and using AssertThrows to create effective test cases.

Testing for Exceptions in JUnit 5

JUnit 5 provides a streamlined way to test exceptions in Java applications. Unlike JUnit 4, which required using the expected attribute or @Rule, JUnit 5 introduces Assertions.assertThrows(), offering a more flexible and readable approach.

Example of Exception Testing in JUnit 5

Consider a method that calculates the square root of a number. If a negative number is provided, it should throw an IllegalArgumentException.

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

class MathUtilsTest {

    double calculateSquareRoot(double number) {
        if (number < 0) {
            throw new IllegalArgumentException("Number must be non-negative");
        }
        return Math.sqrt(number);
    }

    @Test
    void testCalculateSquareRootException() {
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
            calculateSquareRoot(-5);
        });
        assertEquals("Number must be non-negative", exception.getMessage());
    }
}

This test verifies that the method correctly throws an exception when given invalid input, ensuring robustness.

Boundary Value Testing

Boundary Value Testing (BVT) is a technique used to test the limits of input values. It focuses on edge cases, such as minimum and maximum values, where software is most likely to fail.

Example: Boundary Testing for Age Validation

Consider a function that validates a user’s age for registration, allowing only ages between 18 and 65.

boolean isValidAge(int age) {
    return age >= 18 && age <= 65;
}

Boundary tests should check values just inside and just outside the valid range:

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

class AgeValidatorTest {
    
    @Test
    void testAgeBoundaries() {
        assertTrue(isValidAge(18)); 
        assertTrue(isValidAge(65));  
        assertFalse(isValidAge(17)); 
        assertFalse(isValidAge(66)); 
    }
}

BVT ensures the system correctly distinguishes between valid and invalid inputs.

Testing for Exceptions with AssertThrows

The assertThrows method in JUnit 5 simplifies exception testing, making tests more readable and maintainable. It helps validate that methods correctly handle invalid inputs by throwing the expected exceptions.

Example: Division by Zero Handling

Consider a simple method that performs division:

int divide(int dividend, int divisor) {
    if (divisor == 0) {
        throw new ArithmeticException("Cannot divide by zero");
    }
    return dividend / divisor;
}

We can use assertThrows to verify proper exception handling:

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

class DivisionTest {

    @Test
    void testDivideByZero() {
        ArithmeticException exception = assertThrows(ArithmeticException.class, () -> {
            divide(10, 0);
        });
        assertEquals("Cannot divide by zero", exception.getMessage());
    }
}

This ensures that the division method correctly throws an exception when dividing by zero.

Conclusion

Testing exceptions effectively is a vital part of software quality assurance. JUnit 5’s assertThrows method, combined with Boundary Value Testing, enables developers to create thorough test cases that improve the reliability and robustness of applications. By writing well-structured exception tests, developers can prevent unexpected failures and ensure their applications behave as expected under various conditions.

For further reading, check out:

#JUnit5 #ExceptionTesting #AssertThrows #BoundaryValueTesting

From the blog Rick’s Software Journal by RickDjouwe1 and used with permission of the author. All other rights reserved by the author.

Rick Djouwe’s Blog

Hello, and welcome to my blog!

My name is Woubinwou Djouwe Rick Manuel, but most people call me Rick. I am an undergraduate Computer Science student at Worcester State University, and this blog is dedicated to documenting my journey in CS-443: Software Quality Assurance and Testing.

About Me

I have a strong passion for software engineering and artificial intelligence, and I enjoy working on projects that solve real-world problems. Throughout my academic journey, I have gained experience in web development, Python, Java, C++, and database management. I also have a background in tutoring and mentoring students in math and computer science.

From the blog Rick’s Software Journal by RickDjouwe1 and used with permission of the author. All other rights reserved by the author.