여기 내 접근 방식. 4 단계의 리 팩터 테스트이기 때문에 시간면에서 비용이 듭니다.
내가 노출하려고하는 것은 질문의 예에서 노출 된 것보다 복잡한 구성 요소에 더 적합 할 수 있습니다.
어쨌든 전략은 모든 구성 요소 후보가 인터페이스 (DAO, 서비스, 컨트롤러 등)에 의해 정규화되는 데 유효합니다.
1. 인터페이스
MyDocumentService 에서 모든 공용 메소드를 수집하고 이를 모두 인터페이스에 통합 할 수 있습니다. 예를 들어. 이미 존재하는 경우 새로 설정하는 대신 해당 것을 사용하십시오 .
public interface DocumentService {
List<Document> getAllDocuments();
//more methods here...
}
그런 다음 MyDocumentService 가이 새 인터페이스를 구현하도록합니다.
여태까지는 그런대로 잘됐다. 주요 변경 사항은 없었으며 현재 계약을 존중했으며 비 헤이 비는 그대로 남아 있습니다.
public class MyDocumentService implements DocumentService {
@Override
public List<Document> getAllDocuments(){
//legacy code here as it is.
// with no changes ...
}
}
2. 레거시 코드의 단위 테스트
여기에 노력이 있습니다. 테스트 스위트를 설정합니다. 성공적인 사례와 오류 사례를 가능한 한 많이 설정해야합니다. 이것들은 결과의 질을 좋게하기위한 것입니다.
이제 MyDocumentService 를 테스트하는 대신 인터페이스를 테스트 할 계약으로 사용합니다.
세부 사항에 들어 가지 않을 것이므로 용서하십시오. 내 코드가 너무 단순하거나 너무 무관 해 보인다면
public class DocumentServiceTestSuite {
@Mock
MyDependencyA mockDepA;
@Mock
MyDependencyB mockDepB;
//... More mocks
DocumentService service;
@Before
public void initService(){
service = MyDocumentService(mockDepA, mockDepB);
//this is purposed way to inject
//dependencies. Replace it with one you like more.
}
@Test
public void getAllDocumentsOK(){
// here I mock depA and depB
// wanted behaivors...
List<Document> result = service.getAllDocuments();
Assert.assertX(result);
Assert.assertY(result);
//... As many you think appropiate
}
}
이 단계는이 방법에서 다른 것보다 시간이 오래 걸립니다. 미래 비교를위한 참조 지점을 설정하기 때문에 가장 중요합니다.
참고 : 주요 변경 사항이 없었으므로 behaivor는 그대로 유지됩니다. 여기 SCM에 태그를 추가하는 것이 좋습니다. 태그 나 지점은 중요하지 않습니다. 그냥 버전을 만드십시오.
롤백, 버전 비교를 위해 이전 코드와 새 코드를 병렬로 실행할 수 있습니다.
3. 리팩토링
리 팩터는 새로운 컴포넌트로 구현 될 것입니다. 기존 코드는 변경하지 않습니다. 첫 번째 단계는 MyDocumentService를 복사하여 붙여 넣기 하고 이름을 CustomDocumentService로 바꾸는 것만 큼 쉽습니다 (예 :) .
새 클래스는 DocumentService를 계속 구현 합니다. 그런 다음 getAllDocuments ()를 리팩토링 하십시오 . (하나부터 시작하자. 핀 리 팩터)
DAO의 인터페이스 / 방법에 약간의 변화가 필요할 수 있습니다. 그렇다면 기존 코드를 변경하지 마십시오. DAO 인터페이스에서 고유 한 메소드를 구현하십시오. 오래된 코드에 Deprecated 로 주석을 달면 제거해야 할 사항에 대해 나중에 알게됩니다.
기존 구현을 중단 / 변경하지 않는 것이 중요합니다. 두 서비스 를 동시에 실행 한 다음 결과를 비교 하려고합니다 .
public class CustomDocumentService implements DocumentService {
@Override
public List<Document> getAllDocuments(){
//new code here ...
//due to im refactoring service
//I do the less changes possible on its dependencies (DAO).
//these changes will come later
//and they will have their own tests
}
}
4. DocumentServiceTestSuite 업데이트
좋아, 이제 더 쉬운 부분. 새 구성 요소의 테스트를 추가합니다.
public class DocumentServiceTestSuite {
@Mock
MyDependencyA mockDepA;
@Mock
MyDependencyB mockDepB;
DocumentService service;
DocumentService customService;
@Before
public void initService(){
service = MyDocumentService(mockDepA, mockDepB);
customService = CustomDocumentService(mockDepA, mockDepB);
// this is purposed way to inject
//dependencies. Replace it with the one you like more
}
@Test
public void getAllDocumentsOK(){
// here I mock depA and depB
// wanted behaivors...
List<Document> oldResult = service.getAllDocuments();
Assert.assertX(oldResult);
Assert.assertY(oldResult);
//... As many you think appropiate
List<Document> newResult = customService.getAllDocuments();
Assert.assertX(newResult);
Assert.assertY(newResult);
//... The very same made to oldResult
//this is optional
Assert.assertEquals(oldResult,newResult);
}
}
이제 oldResult와 newResult가 독립적으로 검증되었지만 서로 비교할 수도 있습니다. 이 마지막 유효성 검사는 선택 사항이며 결과에 따라 다릅니다. 비교할 수 없을 수도 있습니다.
이 방법으로 두 컬렉션을 비교하기에는 너무 많은 내용이 없지만 다른 종류의 개체 (pojo, 데이터 모델 엔터티, DTO, 랩퍼, 네이티브 형식)에는 유효합니다.
노트
단위 테스트를 수행하는 방법이나 모의 라이브러리를 사용하는 방법을 감히 말하지 않을 것입니다. 나는 당신이 리팩터링을 어떻게해야하는지 말할 것도 없다. 내가하고 싶은 것은 글로벌 전략을 제안하는 것입니다. 앞으로 나아가는 방법은 귀하에게 달려 있습니다. 코드의 복잡성, 복잡성 및 그러한 전략을 시도해 볼 가치가 있는지 정확하게 알 수 있습니다. 여기에는 시간과 자원과 같은 사실이 중요합니다. 또한 향후 이러한 테스트에서 기대할 사항이 중요합니다.
서비스로 예제를 시작했으며 DAO 등을 따릅니다. 의존성 수준에 깊이 들어가기. 다소 위아래 전략 이라고 할 수 있습니다 . 그러나 약간의 변경 / 리 팩터 ( 예 : 투어 예제에서 노출 된 것과 같은 )의 경우 상향식으로 작업이 더 쉬워집니다. 변경의 범위가 적기 때문입니다.
더 이상 사용되지 않는 코드를 제거하고 이전 종속성을 새 코드로 리디렉션하는 것은 사용자의 몫입니다.
더 이상 사용되지 않는 테스트를 제거하면 작업이 완료됩니다. 이전 솔루션의 테스트 버전을 테스트 한 경우 언제든지 서로를 확인하고 비교할 수 있습니다.
수많은 작업의 결과로 레거시 코드를 테스트, 검증 및 버전 화했습니다. 새로운 코드, 테스트, 검증 및 버전 관리가 가능합니다.