Unit Testing
🧪 Unit Testing – A Quick Guide
Unit testing is a software testing technique where individual units or components of a
software are tested in isolation to verify that each part works as expected.
🔍 What Is a "Unit"?
A "unit" is the smallest testable part of an application:
In Python: a function or method
In Java: a class or method
In JS/TS: a module or function
✅ Why Use Unit Testing?
Benefit Explanation
Early bug detection Catches errors before integration or deployment
Easier refactoring Safe to modify code with tests in place
Documentation Tests describe how your functions should behave
Confidence in code changes Ensures new changes don't break existing functionality
🛠️ Common Unit Testing Tools
Language Framework
Python unittest, pytest
Java JUnit, TestNG
JavaScript Jest, Mocha, Jasmine
C# NUnit, MSTest
C++ Google Test
🔍 Best Practices
1. Test one thing per test.
2. Use descriptive test names.
3. Keep tests fast and independent.
4. Mock dependencies (e.g., databases, APIs).
5. Automate test runs (CI/CD pipelines).
✅ What is JUnit?
JUnit is a Java framework used to write and run repeatable unit tests. It helps ensure code
correctness by allowing you to test methods and classes in isolation.
📦 JUnit Versions
Version Description
JUnit 4 Widely used, annotation-based
JUnit 5 Modular, more powerful, includes JUnit Platform + Jupiter + Vintage
We’ll focus on JUnit 5 (a.k.a. Jupiter) as it's the modern version.
🔧 Maven Setup (JUnit 5)
In your pom.xml:
xml
CopyEdit
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version> <!-- Use latest -->
<scope>test</scope>
</dependency>
</dependencies>
✍️ Sample Test Case
Java Class to Test
java
CopyEdit
public class Calculator {
public int add(int a, int b) {
return a + b;
public int divide(int a, int b) {
if (b == 0) throw new IllegalArgumentException("Cannot divide by zero");
return a / b;
JUnit Test Class
java
CopyEdit
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
Calculator calc = new Calculator();
@Test
void testAddition() {
assertEquals(5, calc.add(2, 3));
assertNotEquals(6, calc.add(2, 3));
@Test
void testDivision() {
assertEquals(2, calc.divide(10, 5));
@Test
void testDivisionByZero() {
assertThrows(IllegalArgumentException.class, () -> calc.divide(5, 0));
✅ Common Annotations in JUnit 5
Annotation Description
@Test Marks a test method
@BeforeEach Runs before each test
@AfterEach Runs after each test
@BeforeAll Runs once before all tests (static)
@AfterAll Runs once after all tests (static)
@Disabled Temporarily disables a test
@DisplayName Custom name for test output
📊 Assertion Methods
Method Purpose
assertEquals(expected, actual) Checks equality
assertTrue(condition) Asserts a condition is true
assertFalse(condition) Asserts a condition is false
assertNotNull(obj) Ensures object is not null
assertThrows() Expects an exception
🚀 Running Tests
If you're using Maven:
bash
CopyEdit
mvn test
Or with an IDE like IntelliJ or Eclipse, right-click the test file > Run 'CalculatorTest'.
✅ What is pytest?
pytest is a testing framework for Python that allows you to write simple, scalable, and
readable unit tests. It's more powerful and user-friendly than Python’s built-in unittest.
🔧 Installation
bash
CopyEdit
pip install pytest
📁 File & Function Naming Rules
Test files should be named like test_*.py or *_test.py.
Test functions must start with test_.
✍️ Example: Basic Test
📄 calculator.py (Code to Test)
python
CopyEdit
def add(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
📄 test_calculator.py (Test File)
python
CopyEdit
from calculator import add, divide
import pytest
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
def test_divide():
assert divide(10, 2) == 5
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(5, 0)
🚀 Running Tests
From terminal, just run:
bash
CopyEdit
pytest
To see verbose output:
bash
CopyEdit
pytest -v
🔧 Useful Features in pytest
1. Fixtures (for setup/teardown logic)
python
CopyEdit
import pytest
@pytest.fixture
def sample_data():
return {"a": 5, "b": 3}
def test_add_with_fixture(sample_data):
assert sample_data["a"] + sample_data["b"] == 8
2. Parameterized Tests
python
CopyEdit
import pytest
@pytest.mark.parametrize("a,b,result", [(2, 3, 5), (-1, 1, 0), (0, 0, 0)])
def test_add(a, b, result):
assert add(a, b) == result
3. Skipping Tests
python
CopyEdit
import pytest
@pytest.mark.skip(reason="Under development")
def test_todo():
assert False
4. Temporary Files (tmp_path fixture)
python
CopyEdit
def test_write_file(tmp_path):
f = tmp_path / "temp.txt"
f.write_text("hello")
assert f.read_text() == "hello"
📊 Assertion Examples
Assertion Example
assert a == b Compare values
assert x in y Check for containment
assert not x Check if value is falsy
with pytest.raises(Error) Expect an exception
INTERVIEW QUESTIONS
🔹 1. What is unit testing?
Answer:
Unit testing is a software testing technique where individual components (functions,
methods, or classes) of a program are tested in isolation to verify that they behave as
expected.
🔹 2. Why is unit testing important?
Answer:
Catches bugs early
Makes code easier to maintain
Improves code quality and reliability
Facilitates safe refactoring
Acts as living documentation
🔹 3. What are some popular unit testing frameworks?
Answer:
Language Framework
Python pytest, unittest
Java JUnit, TestNG
JavaScript Jest, Mocha
C# NUnit, MSTest
C++ Google Test
🔹 4. What is the difference between unit testing and integration testing?
Answer:
Unit Testing Integration Testing
Tests individual functions Tests interactions between components
Done in isolation (mocked deps) Requires connected modules or real services
Fast and lightweight Slower due to dependencies
🔹 5. What is mocking in unit testing?
Answer:
Mocking is the process of simulating the behavior of real objects (like databases, APIs,
services) using fake ones. It allows us to test units in isolation without depending on external
systems.
Python: unittest.mock, pytest-mock
Java: Mockito
🔹 6. What is a test fixture?
Answer:
A test fixture is a set of preconditions (setup) needed to run one or more tests. It typically
includes creating test data or initializing resources.
In pytest: use @pytest.fixture
In JUnit: use @BeforeEach, @BeforeAll
🔹 7. How do you handle exceptions in unit tests?
Answer:
Python:
python
CopyEdit
with pytest.raises(ValueError):
divide(5, 0)
Java (JUnit):
java
CopyEdit
assertThrows(IllegalArgumentException.class, () -> divide(5, 0));
🔹 8. What does test coverage mean?
Answer:
Test coverage measures how much of your code is executed by your test suite. High coverage
(e.g. 80%+) generally means more parts of your code are tested.
Python: pytest-cov
Java: JaCoCo
🔹 9. What are assertions in unit testing?
Answer:
Assertions are statements used to check if a condition is true. If the assertion fails, the test
fails.
Examples:
assert a == b (Python)
assertEquals(a, b) (JUnit)
🔹 10. How do you organize test cases?
Answer:
Group related tests in a single file or class
Use meaningful test names
Use setup/teardown functions for reusability
Maintain separate /tests folder
🔹 11. How do you test private methods?
Answer:
Avoid testing private methods directly. Instead, test public methods that use them.
If needed, use reflection (Java) or testing conventions (Python).
🔹 12. What is parameterized testing?
Answer:
Running the same test logic with multiple sets of inputs.
Python (pytest):
python
CopyEdit
@pytest.mark.parametrize("a,b,result", [(2, 3, 5), (0, 0, 0)])
def test_add(a, b, result):
assert add(a, b) == result
JUnit:
java
CopyEdit
@ParameterizedTest
@CsvSource({"2, 3, 5", "0, 0, 0"})
void testAdd(int a, int b, int result) {
assertEquals(result, calc.add(a, b));
🔹 13. What is the lifecycle of a unit test in JUnit or pytest?
JUnit (Java):
@BeforeAll – Run once before all tests (static)
@BeforeEach – Run before each test
@Test – Test method
@AfterEach – Run after each test
@AfterAll – Run once after all tests (static)
pytest (Python):
@pytest.fixture(scope="module"/"function") – for setup/teardown
yield – used inside fixtures to define teardown code
🔹 14. What is test-driven development (TDD)?
Answer:
TDD is a development approach where you:
1. Write a failing test
2. Write the minimum code to pass it
3. Refactor the code
Repeat the cycle.
🔹 15. Can unit tests replace QA testing or manual testing?
Answer:
No. Unit tests cover only low-level correctness. Manual, integration, UI, performance, and
user acceptance tests are still needed for full coverage.