alpha 디지털 비교기의 테스트 구동 실현

이번에 나는 나의 동료인 토마스즈 지허쉬즈GOD Nearshore SE가 쓴 글을 공유하고 있다.
간단히 말해 테스트 드라이브 개발(Test driven development, TDD)은 비즈니스 코드 이전에 자동 테스트를 생성한다고 가정하는 민첩한 구현 방식이다.이런 방법의 목표는 실현된 실제 진도를 추적하는 것이지만 코드를 재구성하거나 정리하는 데도 도움이 된다.
본고의 목표는 실용적인 방식으로 테스트 구동의 개발 방법을 보여주는 것이다.본문에서 나는 JAVA와 JUnit 프레임워크를 어떻게 사용하여 알파벳 숫자 정렬을 실현하는지 소개할 것이다.
요구 사항
그 중 하나는 트리의 노드를 알파벳 숫자순으로 정렬하는 것이다.
알파벳 숫자 순서는 숫자를 포함하는 노드는 숫자에 따라 정렬해야 한다는 것을 의미한다.문자열과 다릅니다(문자열 정렬 순서가 "노드 2"이전의 "노드 10"은 문자열이 비교될 때까지 문자를 하나씩 비교하기 때문입니다. 그 다음에 서로 다른 문자의 결과가 전체 문자열의 비교에 영향을 줄 수 있습니다. 이것이 바로 "노드 10"이 "노드 2"앞에 있을 수 있는 이유입니다.
이 요구는 전도 0과 자모 접미사도 포함하지만 자연수만 주목하는 것은 마이너스를 고려하지 않는다는 뜻이다.
온전한 요구는 표1을 참조한다.

표 1.숫자를 포함하는 문자열의 알파벳 숫자 정렬

시작 방법


본고는 문자열 비교기의 기본적인 실현을 소개할 것이다.
1 class AlphaNumericalComparator implements Comparator<String> { 
2 @Override 
3 public int compare(String o1, String o2) { 
4 return o1.compareTo(o2); 
5 } 
6 } 

어떻게 시험을 준비합니까


현재, 실현된 진도를 검사하기 위해 JUnit 테스트를 준비해야 한다.다음 테스트는 이 요구를 정확하게 포괄했는지 확인하기 위한 것이다.
본문에서 가장 뚜렷한 상황에 주목합시다.
• threeNodes() - 포함된 숫자에 따라 문자열 정렬 테스트
• leadingZero() - 리딩 제로를 포함하는 문자열이 리딩 제로를 포함하지 않는 문자열 앞에 있는지 테스트합니다.
• 접미사() - 접미사가 있는 문자열의 정렬 여부를 테스트합니다.
• alphanumerical() - 모든 요구 사항 포함
1 @Test 
2 public void threeNodes() { 
3 List<String> actuals = Arrays.asList("node 2", "node 1", "node 10"); 
4 List<String> expected = Arrays.asList("node 1", "node 2", "node 10"); 
5 6 
Collections.sort(actuals, new AlphaNumericalComparator()); 
7 Assert.assertEquals(expected, actuals); 
8 } 
9 
10 @Test 
11 public void leadingZero() { 
12 List<String> actuals = Arrays.asList("node 1", "node 01"); 
13 List<String> expected = Arrays.asList("node 01", "node 1"); 
14 
15 Collections.sort(actuals, new AlphaNumericalComparator()); 
16 Assert.assertEquals(expected, actuals); 
17 } 
18 
19 @Test 
20 public void suffix() { 
21 List<String> actuals = Arrays.asList("node 1a", "node 1"); 
22 List<String> expected = Arrays.asList("node 1", "node 1a"); 
23 
24 Collections.sort(actuals, new AlphaNumericalComparator()); 
25 Assert.assertEquals(expected, actuals); 
26 } 
27 
28 @Test 
29 public void alphaNumerical() { 
30 List<String> actuals 
31 = Arrays.asList("node 2", "node 1", "node 10", "node 1a", "node 01"); 
32 List<String> expected 
33 = Arrays.asList("node 01", "node 1", "node 1a", "node 2", "node 10"); 
34 
35 Collections.sort(actuals, new AlphaNumericalComparator()); 
36 Assert.assertEquals(expected, actuals); 
37 } 
First execution의 결과는 표 2와 같습니다.일반적인 유사한 문자열을 사용하는 비교기는 두 개의 실패한 테스트가 있습니다.
이렇게 하는 이유 중 하나는 주어진 문자열 (정렬할 문자열은 숫자를 포함) 을 이 비교기로 정확하게 정렬할 수 없기 때문이다.

표 2.1차 집행 결과.

지정된 입력 분할


입력 문자열을 비교하기 위해 가능한 숫자를 고려하여 주어진 입력은 숫자와 비숫자 부분으로 나누어야 한다.이 부분은 다음 문장에서 '그룹' 이라고 부른다.
예: 지정된 문자열은 다음 그룹으로 나누어야 합니다.
"10node 2abc100" -! "10"; "node "; "2"; "abc"; "100" 
If the input string is splitted correctly we test with the test below: 
1 @Test 
2 public void split() { 
3 String actuals = "10node 2abc100"; 
4 List<String> expected = Arrays.asList("10", "node ", "2","abc","100"); 
5 Assert.assertEquals(expected, AlphaNumericalComparator.split(actuals); 
6 } 
분할 방법의 실현은 정규 표현식을 사용하여 수치와 비수치 그룹을 찾습니다.
다음 표현식은 비교기의 필드로 정의됩니다.
1 private static final String digit = "\\d+"; 
2 private static final String nonDigit = "\\D+"; 
3 private static final Pattern pattern = Pattern.compile(digit + "|" + nonDigit); 
Spliting 함수는 comparator 클래스의 한 방법으로 구현되며 다음과 같은 구현이 있습니다.
1 public static List<String> split(String toSplit) { 
2 List<String> splitted = new ArrayList<String>(); 
3 Matcher m = pattern.matcher(toSplit); 
4 while (m.find()) { 
5 splitted.add(m.group()); 
6 } 
7 return splitted; 
8 } 
문자열을 올바르게 분할한 후 그룹 비교를 실행할 수 있습니다.

계산법


그룹 비교(유사 문자열)가 같으면 건너뛰고 다음 그룹을 비교할 수 있습니다.
방법compare () 는 비교적 같은 그룹이 아닌 같은 그룹을 건너뛸 수 있도록 확장됩니다.compare () 는 이미 정의되고 테스트된 split () 방법을 사용하여 그룹을 추출합니다.
1 @Override 
2 public int compare(String o1, String o2) { 
3 List<String> groups1 = split(o1); 
4 List<String> groups2 = split(o2); 
5 6 
for (int i = 0; i < Math.max(groups1.size(), groups2.size()); i++) { 
7 String group1 = groups1.get(i); 
8 String group2 = groups2.get(i); 
9 
10 if (group1.equals(group2)) { 
11 continue; 
12 } 
13 return group1.compareTo(group2); 
14 } 
15 return o1.compareTo(o2); 
16 } 

표 3:.두 번째 집행 결과.
시험 결과는 표3과 같다.수정된compare () 방법을 사용하면 접미사 () 테스트에 실패할 수 있습니다.중요한 것은 Index Out Of Bounds Exception 때문에 Alphanumeric () 와 suffix () 테스트가 실패했습니다.
이 이상은 추출된 그룹 수가 다르기 때문입니다.
이런 예외적인 상황을 피하기 위해서는 비교가 가능할 것이다.비교 그룹의 수가 다른 경우 기존 그룹을 빈 문자열과 비교해야 합니다.
1 String group1 = getEmptyWhenNoGroups(groups1, i); 
2 String group2 = getEmptyWhenNoGroups(groups2, i); 
3 4 
private String getEmptyWhenNoGroups(List<String> groups, int i) { 
5 return groups.size() > i ? groups.get(i) : ""; 
6 } 

표 4.셋째, 집행 결과.
표4는 그룹 수가 같지 않을 때 빈 문자열을 비교한 테스트 결과를 보여 준다.
Index OutOf Bounds Exception은 더 이상 없지만 두 가지 테스트가 실패했습니다.숫자의 정렬이 정확하지 않기 때문이다.이제 비교 등의 숫자를 도입할 것이다.
숫자 그룹을 숫자로 비교하기 위해서 우리는 정수를 사용하여 그것들을 정수로 해석할 수 있다.parseInt () 방법입니다.정수를 사용합니다.그러나 가능하다면 우리는 이 질문에 대답할 수 있어야 한다. 해석된 숫자는 정수를 초과할 수도 있다.최대치.시작할 때, 우리는 수치 그룹이 최대 정수치를 초과해서는 안 된다고 가정한다.
따라서 두 그룹이 모두 숫자인 경우 숫자로 비교해야 하며 그렇지 않으면 문자열을 앞과 같이 사용해야 합니다.
1 if (group1.matches(digit) && group2.matches(digit)) { 
2 int int1 = Integer.parseInt(group1); 
3 int int2 = Integer.parseInt(group2); 
4 5 
return int1 - int2; 
6 } 

표 5.넷째, 집행 결과.
표5는 주어진 문자열의 숫자 부분을 숫자로 비교한 테스트 결과를 제시했으나 leadingZero() 테스트가 실패했다.원인은 바로 이 정수다.parseInt () 방법, 전도 0이 있는 숫자 - 정수의 결과를 구분하지 않습니다.parseInt("1") 및 정수.parseInt("01")는 와 같습니다.
리딩 제로를 고려하는 숫자를 구분하려면 숫자 그룹을 일반 문자열과 비교해야 합니다. 그렇지 않으면 숫자와 비교해야 합니다.
1 return int1 == int2 ? group1.compareTo(group2) : int1 - int2; 

표 6.최종 집행 결과.
표6는 전도 0을 고려한 테스트 결과를 제시했다.모든 테스트가 통과되었다.
이제 큰 숫자 문제로 돌아가자.추가 bigNumbers() 테스트를 사용하여 동작을 검사하려고 시도하면 NumberFormatException이 발생합니다.이 작업을 수행하면 NumberFormatException이 예상대로 꺼집니다.
1 @Test 
2 public void bigNumbers() { 
3 List<String> actuals = Arrays.asList("a1000000000000000", "a1000000000000001"); 
4 List<String> expected = Arrays.asList("a1000000000000000", "a1000000000000001"); 
5 6 
Collections.sort(actuals, new AlphaNumericalComparator()); 
7 Assert.assertEquals(expected, actuals); 
8 } 
이 이상을 처리하는 가장 간단한 방법은 해석된 숫자가 영원히 초과되지 않도록 숫자 그룹의 크기를 제한하는 것이다
허용되는 최대 수량입니다.어떻게?정의된regexp 추출 숫자를 되돌려주고 현재 변경
표현식 은 해석 숫자 의 길이 가 6 자리 를 넘지 않도록 함으로써 우리 는 확정할 수 있다
허용된 정수 크기를 초과하지 않았습니다.
1//private static final String digit=“\d+”;
2 사유 정적 최종 문자열 숫자 = "\d{1,6}"
요약
수요는 진실한 항목에서 나온다.평가할 때, 나는 이러한 수요를 만족시킬 기존의 해결 방안을 찾을 수 없다.프로그래밍 연습으로서, 나는 알고리즘을 스스로 실현하기로 결정했다. 왜냐하면 보통 나는 어떤 코드 줄도 쓰지 않기 때문이다.그 밖에 나는 이 글을 써서 알고리즘의 테스트 구동 실현 방식을 보여주고 싶다.

좋은 웹페이지 즐겨찾기