2017-01-24 5 views
0

나는 starting 테스트를 담당하는 TestExecutor라는 자바 클래스를 가지고있다. 위의 작업을 각각 수행 내가 TestExecutor 클래스의 private 메소드를 생성 한 각 단계에 대한Java에서 좋은 객체 지향 디자인 예제

- Update test repository 
- Locate the test script 
- Create result empty directory 
- Execute command 
- Parse output 
- Update database 

, 모든 시도-catch 블록에 둘러싸여 : 테스트를 시작하는 단계의 수를 포함한다. 필자는 클래스가 너무 많아서 좋은 디자인이 아니라는 사실을 알고 있으며 많은 양의 기능이 개인 메서드에 숨겨져 단위 테스트에 고통을줍니다.

위의 구조와 비슷한 것으로부터 벗어나는 방법을 모르겠으므로이 클래스를 리팩터링하는 것에 대한 의견을 듣고 싶습니다. 아래의 코드 예는 다음과 같습니다.

public void start() throws TestExecuteException { 
    try { 
     updateRepository(); 
     locateScript(); 
     createResultDirectory(); 
     executeCommand(); 
     parseOutput(); 
     updateDatabase(); 
    catch(a,b,c) { 
    } 
} 

private updateRepository() { 
    // Code here 
} 
// And repeat for other functions 
+0

귀하의 방법은 공개되지 않는 이유는 무엇입니까? 클래스가 단일 책임을 가지고있는 한 단일 클래스에서 여러 메소드를 갖는 데는 아무런 문제가 없습니다. – underdog

+0

TestExecutor 외부에서 메서드를 호출 할 필요가 없으므로 메서드를 비공개로 만들기로 결정했습니다. 내 문제는 클래스가 하나의 일반적인 책임 (테스트 실행)을 가지고 있지만 그 아래에 여러 가지 책임이 있다는 것입니다 (레지스트리 업데이트, 스크립트 찾기 등) – Adam

+0

@Adam 제공 한 답변을 검토하고 더 명확히하기 위해 의견을 말하십시오. . 어떤 답변이 도움이 되었다면, 당신은 그들을 upvote 수 있습니다. 가장 유용한 답변 옆에있는 눈금을 클릭하여 답변을 수락 할 수도 있습니다. [누군가 내 질문에 대답 할 때 무엇을해야합니까?] (http://stackoverflow.com/help/someone-answers)를 읽어보십시오. 투표는 무료입니다. 그것은 비용이 들지 않습니다. 대답을 수락하면 +2의 답을 얻을 수 있습니다. 그래서 부끄러워하지 마십시오. 가서 돈을 지불하십시오! – CKing

답변

0

잘 클래스가 저에게 잘 보입니다.

나는이 내 클래스

는 지금까지 클래스는 하나의 책임이 같은 방법의 수는 중요하지 않습니다 너무 많이처럼 좋은 디자인이 아니라는 것을 알고 있어요.

확인하십시오. template method design pattern 당신의 클래스는 추상적 인 Game 클래스가하는 것과 유사한 것을하고 있습니다.

public abstract class Game { 
    abstract void initialize(); 
    abstract void startPlay(); 
    abstract void endPlay(); 

    //template method 
    public final void play(){ 

     //initialize the game 
     initialize(); 

     //start game 
     startPlay(); 

     //end game 
     endPlay(); 
    } 
} 

및 때문에 개인 방법을 테스트하는 방법에 대한 & this 읽기 this 개인 방법

에 숨겨진 된 기능 많은 양으로도 단위 테스트에 고통입니다. 테스트 할 수없는 코드를 테스트하는 데 도움이되는 PowerMock과 같은 프레임 워크를 사용할 수도 있습니다.

+0

클래스에는 여러 가지 책임이있는 것 같습니다. 1) 데이터베이스와 대화하십시오. 2) 전화 번호부에 말하십시오. 3) 데이터를 분석하고 결과를 만듭니다. – CKing

0
내가 당신은 확실히 SOLID에서 살펴 보셔야 상기 구조

비슷한로부터 멀리하는 방법을 잘 모르겠어요으로이 클래스를 리팩토링에 대한 귀하의 의견을 듣고 싶습니다

깨끗하고 테스트 가능한 객체 지향 코드를 작성하는 출발점의 원칙. 내 경력을 시작할 때 그 사실을 알게되었고,이 원칙을 지키는 것이 많은 도움이되었습니다.

그렇다면 관련 기능을 다른 클래스로 그룹화하여 시작하겠다고합니다. 예를 들어 updateRepository()updateDatabase()DatabaseHelper이라는 별도 클래스로 이동할 수 있습니다. 마찬가지로 locateScript()createResultDirectory()은 디스크 관련 작업으로 보이며 DirectoryHelper이라는 별도의 클래스로 이동할 수 있습니다. 나는 당신이 그것의 요지를 얻는다고 믿습니다. 방금 성취 한 것은 우려의 분리입니다.

이제 별도의 수업이 있으므로 수업을 함께 가져 와서 작동시켜야합니다. TestExecutor에 계속 나열 할 수있는 methods이 계속 표시 될 수 있습니다. 유일한 차이점은이 메소드가 이제 위에서 만든 개별 클래스에 작업을 위임한다는 것입니다. 이를 위해 TestExecutor에는 DatabaseHelperDirectoryHelper 클래스에 대한 참조가 필요합니다.TestExecutor 안에 직접 이러한 클래스를 인스턴스화 할 수 있습니다. 그러나 이는 TestExecutor이 구현과 밀접하게 결합되어 있음을 의미합니다. 대신 할 수있는 일은 TestExecutor 외부 코드를 사용하여 DatabaseHelpeDirectoryHelper을 제공하는 것입니다. 이것은 종속성 반전에서 종속성 주입으로 알려져 있습니다. 이 접근법의 장점은 이제 DatabaseHelperDirectoryHelper의 하위 클래스를 TaskExecutor에 전달할 수 있으며 구현의 세부 사항을 알 필요가 없다는 것입니다. 이것은 TaskExecutor의 단위 테스팅에서 실제 인스턴스를 전달하는 대신 이러한 종속성을 조롱함으로써 용이하게합니다.

나는 나머지 SOLID 원칙을 탐구하고, 구현하고, 평가할 수 있도록 남겨 둘 것입니다.

0

나는 이렇게 할 것이다. 첫째, 각 테스트 단계에 있어야하는 계약을 시행하십시오.

interface TestCommand{ 
    void run(); 
} 

이제 테스트 명령을 별도의 클래스로 만듭니다. 비슷한 유형의 명령을 재사용 할 수 있도록 이러한 명령 클래스를 일반 클래스로 만들어보십시오. 이제 테스트를 실행하려는 클래스에서 다음과 같이 테스트 단계를 구성하십시오.

//in your test class do this. 
List<TestStep> testCommands = new ArrayList<>(); 
testCommands.add(new UpdateRepoCommand()); 
testCommands.add(new LocateScriptCommand()); 
// and so on.... 

이제 모든 단계를 시간순으로 실행하십시오.

public void start(testSteps) throws TestExecuteException { 
    try { 
     for(TestCommand command : testCommands){ 
      command.run() 
    }   
    catch(Exception e) { 
     //deal with e 
    } 
} 

또한 위에서 설명한 CKing은 이러한 테스트 단계에서 SOLID 원칙을 따릅니다. 의존성을 주입하고 단위 테스트를 별도로 작성하십시오.