Why Write Test Code
- Documentation of code
- To discover defects in code
- To ensure stability during refactoring
What is TDD?
- Test Driven Development
- A development method where test code is written before production code
- TFD (Test First Development) + Refactoring
- Verify functionality first (at the method level)
What about BDD?
- Behavior Driven Development
- A method of writing test code based on scenarios
- Each scenario follows a Given / When / Then structure
Password Validator
Requirements and Specifications
- Password must be at least 9 characters and no more than 15 characters
- Throw an Exception if password is less than 9 or more than 15 characters
- Verify boundary conditions
Dependency
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
testImplementation 'org.assertj:assertj-core:3.23.1'
}
test {
useJUnitPlatform()
}
Writing Password Length Validation Test Code
Creating Test Class and Basic Class
- It’s best if the test code package location matches the main source package location
- First implement requirements in test code, then gradually create parts in actual code that haven’t been implemented yet
package org.example;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThatCode;
/**
* Password must be at least 9 characters and no more than 15 characters
* Throw Exception if password is less than 9 or more than 15 characters
* Verify boundary conditions
*/
public class PasswordValidatorTest {
@DisplayName("Password is valid if at least 9 and at most 15 characters") // Test intent
@Test
void validatePasswordTest() {
assertThatCode(() -> PasswordValidator.validate("123456789"))
.doesNotThrowAnyException();
}
}
- After writing, a red line appears for the PasswordValidator class
- Create PasswordValidator in main source
- Create validate method in PasswordValidator class
package org.example;
public class PasswordValidator {
public static void validate(String password) {
}
}
- Run test -> Success
Refactoring Created Classes to Reflect Detailed Conditions
- Check if the input string is at least 9 and at most 15 characters, throw Exception if not
package org.example;
public class PasswordValidator {
public static final String WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE = "Password must be at least 9 and at most 15 characters.";
public static void validate(String password) {
int length = password.length();
if (length < 9 || length > 15) {
throw new IllegalArgumentException(WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE);
}
}
}
Testing When Password is Less Than 9 Characters
- Using the same approach: try in TestCode first, then implement in actual code one by one
- Since Exception handling is already written, there’s not much to modify - just test the condition
public class PasswordValidatorTest {
@DisplayName("Exception thrown when password is less than 9 characters")
@Test
void validatePasswordShortExceptionTest() {
assertThatCode(() -> PasswordValidator.validate("1234"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(PasswordValidator.WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE);
}
}
Testing When Password Exceeds 15 Characters
- Using the same approach: try in TestCode first, then implement in actual code one by one
- Since Exception handling is already written, there’s not much to modify - just test the condition
public class PasswordValidatorTest {
@DisplayName("Exception thrown when password exceeds 15 characters")
@Test
void validatePasswordLongExceptionTest() {
assertThatCode(() -> PasswordValidator.validate("1234512345123456"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(PasswordValidator.WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE);
}
}
Testing Boundary Conditions
- The password length that meets our requirements is at least 9 and at most 15 characters
- The boundary values for this condition are passwords of 8 or 16 characters
- Adding tests for boundary values helps create good tests
- Let’s test using
@Parameterize
Adding Dependency
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0'
Testing with Parameterize
public class PasswordValidatorTest {
@DisplayName("Test boundary conditions")
@ParameterizedTest
@ValueSource(strings = {"12345678", "1234567890123456"})
void validatePasswordBoundaryTest(String password) {
assertThatCode(() -> PasswordValidator.validate(password))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(PasswordValidator.WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE);
}
}
- Values inside ValueSource are automatically cycled through during execution
- Data declared in ValueSource can be received one by one in the function
- When executed, unlike other tests, this test runs twice
Result Screen

댓글남기기