JUnit 프레임워크
- JUnit은 자바 프레임워크 중에서 가장 유명하다.
- 오류를 파악할 때 유용한 코드를 제공한다.
- 테스트 케이스가 모든 행, 모든 if문, 모든 for문을 실행한다. 이것은 모듈이 올바르게 동작한다는 것을 의미한다
ComparsionCompactor 모듈 개선하기
- 두 문자열을 받아 차이를 반환하는 모듈이다.
package junit.framework;
public class ComparisonCompactor {
private static final String ELLIPSIS = "...";
private static final String DELTA_END = "]";
private static final String DELTA_START = "[";
private int fContextLength;
private String fExpected;
private String fActual;
private int fPrefix;
private int fSuffix;
public ComparisonCompactor(int contextLength, String expected, String actual) {
fContextLength = contextLength;
fExpected = expected;
fActual = actual;
}
public String compact(String message) {
if (fExpected == null || fActual == null || areStringsEqual()) {
return Assert.format(message, fExpected, fActual);
}
findCommonPrefix();
findCommonSuffix();
String expected = compactString(fExpected);
String actual = compactString(fActual);
return Assert.format(message, expected, actual);
}
private String compactString(String source) {
String result = DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
if (fPrefix > 0) {
result = computeCommonPrefix() + result;
}
if (fSuffix > 0) {
result = result + computeCommonSuffix();
}
return result;
}
private void findCommonPrefix() {
fPrefix = 0;
int end = Math.min(fExpected.length(), fActual.length());
for (; fPrefix < end; fPrefix++) {
if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix)) {
break;
}
}
}
private void findCommonSuffix() {
int expectedSuffix = fExpected.length() - 1;
int actualSuffix = fActual.length() - 1;
for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) {
if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix)) {
break;
}
}
fSuffix = fExpected.length() - expectedSuffix;
}
private String computeCommonPrefix() {
return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
}
private String computeCommonSuffix() {
int end = Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length());
return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : "");
}
private boolean areStringsEqual() {
return fExpected.equals(fActual);
}
}
- 긴 표현식 몇 개와 이상한 +1 등이 거슬린다.
- 하지만 전반적으로 상당한 모듈이다.
1. 접두어 삭제
- 변수 이름에 범위를 명시할 필요 없다. 제거하자.
// 기존 코드
public class ComparisonCompactor {
...
private int fContextLength;
private String fExpected;
private String fActual;
private int fPrefix;
private int fSuffix;
...
}
// 개선된 코드
public class ComparisonCompactor {
...
private int ContextLength;
private String Expected;
private String Actual;
private int Prefix;
private int Suffix;
...
}
2. 의도를 명확하게 하기 위해 조건문을 캡슐화
- 조건문을 메서드로 뽑아내 적절한 이름을 붙인다.
// 기존 코드
public String compact(String message) {
if (fExpected == null || fActual == null || areStringsEqual()) {
return Assert.format(message, expected, actual);
}
findCommonPrefix();
findCommonSuffix();
String expected = compactString(this.expected);
String actual = compactString(this.actual);
return Assert.format(message, expected, actual);
}
// 개선된 코드
public String compact(String message) {
if (shouldNotCompact()) {
return Assert.format(message, fExpected, fActual);
}
findCommonPrefix();
findCommonSuffix();
String expected = compactString(this.expected);
String actual = compactString(this.actual);
return Assert.format(message, expected, actual);
}
private boolean shouldNotCompact() {
return fExpected == null || fActual == null || areStringsEqual();
}
3. 함수에서 멤버 변수와 이름이 똑같은 변수는 지양한다.
// 기존 코드
public String compact(String message) {
if (shouldNotCompact()) {
return Assert.format(message, fExpected, fActual);
}
findCommonPrefix();
findCommonSuffix();
String expected = compactString(this.expected);
String actual = compactString(this.actual);
return Assert.format(message, expected, actual);
}
// 개선된 코드
public String compact(String message) {
if (shouldNotCompact()) {
return Assert.format(message, fExpected, fActual);
}
findCommonPrefix();
findCommonSuffix();
String compactExpected = compactString(this.expected);
String compactActual = compactString(this.actual);
return Assert.format(message, compactExpected , compactActual );
}
4. 긍정형 조건문을 사용한다.
- 부정문은 긍정문보다 한 번 더 꼬아서 이해해야 한다.
- 때문에 if문은 긍정으로 만드는 것이 좋다.
public String compact(String message) {
if (canBeCompacted()) {
return Assert.format(message, fExpected, fActual);
}
findCommonPrefix();
findCommonSuffix();
String expected = compactString(this.expected);
String actual = compactString(this.actual);
return Assert.format(message, expected, actual);
}
private boolean canBeCompacted() {
return fExpected != null || fActual != null || !areStringsEqual();
}
5. 기능에 맞는 함수 이름을 부여한다.
- 아래의 코드는 문자열을 압축하는 함수라지만 실제로 압축하지 않는다. 때문에 적합한 이름으로 바꾸어 주었다.
// 기존 코드
public String compact(String message) {
...
}
// 개선된 코드
public String formatCompactedComparison(String message) {
...
}
6. 메서드를 분리한다.
- 메서드가 하나의 기능만 하도록 분리한다.
// 기존 코드
public String compact(String message) {
if (canBeCompacted()) {
return Assert.format(message, fExpected, fActual);
}
findCommonPrefix();
findCommonSuffix();
String expected = compactString(this.expected);
String actual = compactString(this.actual);
return Assert.format(message, expected, actual);
}
// 개선된 코드
public String formatCompactedComparison(String message) {
if (canBeCompacted()) {
compactExpectedAndActual();
return Assert.format(message, compactExpected, compactActual);
} else {
return Assert.format(message, expected, actual);
}
}
private void compactExpectedAndActual() {
findCommonPrefix();
findCommonSuffix();
compactExpected = compactString(expected);
compactActual = compactString(actual);
}
7. 함수 사용방식은 일관적이어야 한다.
// 기존 코드
private void compactExpectedAndActual() {
findCommonPrefix();
findCommonSuffix();
compactExpected = compactString(expected);
compactActual = compactString(actual);
}
// 개선된 코드
private void compactExpectedAndActual() {
prefixIndex = findCommonPrefix();
surfixIndex = findCommonSuffix();
compactExpected = compactString(expected);
}
'Book > 클린코드' 카테고리의 다른 글
[클린코드] 17장 냄새와 휴리스틱 (일반) (1) | 2023.09.21 |
---|---|
[클린코드] 16장 SerialDate 리팩토링 (0) | 2023.09.21 |
[클린코드] 14장 점진적인 개선 (0) | 2023.09.21 |
[클린코드] 13장 동시성 (0) | 2023.09.17 |
[클린코드] 12장 창발성(創發性) (0) | 2023.09.17 |