Category Archives: CS-443

Unit Testing and Testable Code


Unit testing is a fundamental practice in software development, ensuring that individual units of code work as expected. However, the real challenge often lies in writing code that is easy to test. Poorly designed, untestable code can complicate unit testing and introduce expensive complexity. In this blog post, we’ll explore the importance of writing testable code, the common pitfalls that make code hard to test, and the benefits of adopting testable coding practices.

The Significance of Unit Testing

Unit testing involves verifying the behavior of a small portion of an application independently from other parts. A typical unit test follows the Arrange-Act-Assert (AAA) pattern: initializing the system under test, applying a stimulus, and observing the resulting behavior. The goal is to ensure that the code behaves as expected and meets the specified requirements.

However, the ease of writing unit tests is significantly influenced by the design of the code. Code that is tightly coupled, non-deterministic, or dependent on mutable global state is inherently difficult to test. Writing testable code is not only about making testing less troublesome but also about creating robust and maintainable software.

Common Pitfalls in Writing Testable Code

Several factors can make code challenging to test, including:

  1. Tight Coupling: Code that is tightly coupled to specific implementations or data sources is difficult to isolate for testing. Decoupling concerns and introducing clear seams between components can enhance testability.
  2. Non-Deterministic Behavior: Code that depends on mutable global state or external factors (e.g., current system time) can produce different results in different environments, complicating testing. Making code deterministic by injecting dependencies can address this issue.
  3. Side Effects: Methods that produce side effects (e.g., interacting with hardware or external systems) are hard to test in isolation. Employing techniques like Dependency Injection or using higher-order functions can help in decoupling and testing such code.

Benefits of Testable Code

Adopting testable coding practices offers several benefits:

  1. Improved Code Quality: Testable code is typically well-structured, modular, and easier to understand. This leads to higher code quality and reduces the likelihood of bugs.
  2. Easier Maintenance: Code that is easy to test is also easier to maintain. Changes can be made with confidence, knowing that unit tests will catch any regressions.
  3. Faster Development: With a robust suite of unit tests, developers can iterate quickly and confidently, reducing the time spent on manual testing and debugging.
  4. Enhanced Collaboration: Clear and testable code promotes better collaboration among team members, as the intent and behavior of the code are easier to comprehend.

Conclusion

Writing testable code is a crucial aspect of software development that extends beyond the realm of testing. It encompasses good design principles, decoupling, and the elimination of non-deterministic behavior and side effects. By focusing on writing testable code, developers can create software that is not only easier to test but also more robust, maintainable, and reliable. Embracing these practices ultimately leads to higher quality software and more efficient development processes.

All of this comes from the link below:

https://www.toptal.com/qa/how-to-write-testable-code-and-why-it-matters


From the blog CS@Worcester – aRomeoDev by aromeo4f978d012d4 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Always Improving Software

In this post, I’ll be discussing my thoughts primarily on Chapter 1 of Apprenticeship Patterns, a book I had to read parts of for another class. I really like the idea of being a “Software Apprentice,” as I think it is a good representation of the attitude I have adopted over the years. I’ve always viewed myself as someone who is constantly learning and evolving in this field, and the apprenticeship model seems to align perfectly with that. It’s not about arriving at some endpoint but about growing, making mistakes, and improving.

What stood out to me the most was the idea of viewing the development process as a journey, not a destination. Chapter 1 introduces the concept of “Software Craftsmanship” as more than just technical skill, but also as a mindset of continuous learning. This was particularly thought-provoking because I think there’s a tendency, especially early in our careers, to think of coding as a task to be completed or a skill to be mastered and then moved beyond while in pursuit of some computer science career. However, the idea that becoming a Software Craftsman is an ongoing process—a commitment to constant improvement and a mindset that thrives on learning—is something that I think is a better description. It shifted my perspective on what it means to be good at coding- it’s not enough to know how to do something today, it’s about always finding a way to improve your code in the future.

In the past, specifically in my career, I’ve often gotten caught up in the day-to-day rush of just getting whatever piece of code done. I’ve rushed to get things coded, with the focus being on completing projects rather than developing deeper expertise or refining my approach to coding. After reading this chapter, I think I’m more likely to focus on the long-term value of writing quality code and the importance of standards. It’s not just about writing code that works; it’s about writing code that lasts, is readable, and contributes to a more sustainable project. I’m going to start to approach my coding tasks with a deeper goal, rather than rushing through them for the sake of completion.

I think this is particularly applicable to Software Quality Assurance and Testing because QA is, in essence, a form of ensuring that our code is always improving. Not only do we need to find a balance between constantly improving before release and actually releasing, but even after releases, we still need to be looking for future requirements and improvements. There is no end in sight for software testing, ever. I think this constant forward motion, driven by constantly increasing requirements, is inseparable from the idea of being a software apprentice.

From the blog Mr. Lancer 987's Blog by Mr. Lancer 987 and used with permission of the author. All other rights reserved by the author.

Software Testing Thinking Hats

The blog post I’ve chosen talks about the different mind sets that you should use when tackling different situations. When writing tests, it helps to write tests with different goals so that you don’t forget to test every aspect of some section of code. The blog author talks about how trying to do the tests out of order or without any order in mind you can forget things and cause it to take more time in the long run. The author categorizes these as “hats” to wear during each progressive stage. There is the ambitious hat which is for when you are testing the code in the way the customer will be using the code. There is then an uncomfortable hat which is for when your tests are failing, and you need to fix what you can in your testing. The confident hat is the one you can wear while you are refactoring your code and running just to confirm everything passes. The author also makes specific mention to not try and wear multiple hats at once.
From my experience in the classes I’ve taken so far, I’ve done some built in testing in files for whole programs that I myself have written, and so I know exactly what the code should do, what I need to have pass in order to meet the homework criteria. In these cases, because I am both the author of the code and the author of the test cases, I am able to make edits in both parts with the knowledge of exactly what the test cases should be. This has helped in my current class so far but as we move forward, we will be approaching testing like it is done in the workplace and when the people testing the code are a separate group that has not touched the program code. I’ve definitely seen myself as the coder that the author describes who frantically moves around the code and tests trying whatever I can to get everything to work instead of approaching it with any methodology. I want to become both better and more efficient at testing code as it will help me write code also and further my understanding of what makes a complete program. Testing is a big part of working in the computer science field and I know that quality assurance is very important, so I look forward to both learning more about this within the course and doing more blogs about the industry.

Chris James – The TDD Thinking Hats

From the blog CS@Worcester – Computer Science Blog by dzona1 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.