2017-10-10 27 views
1

Swing으로 Java 데스크탑 애플리케이션을 개발하는 동안, 단위 테스트를 통해 기본 컨트롤러/모델 클래스가 아닌 UI를 직접 테스트해야합니다.시작하기 : AssertJ Swing으로 Java Swing GUI 테스트하기

answer (on "What is the best testing tool for Swing-based applications?")FEST을 사용하여 제안했지만, 불행히도 중단되었습니다. 그러나 FEST가 나온 곳에서 계속 진행되는 몇 가지 프로젝트가 있습니다. 단위 테스트에서 이전에 사용한대로 (특히 answer에서 언급 한) 제가주의를 끌었습니다 : AssertJ.

분명히 FEST를 기반으로하고 Swing UI 테스트를 작성하는 데 사용하기 쉬운 몇 가지 방법을 제공하는 AssertJ Swing이 있습니다. 하지만 초기/작업 설정을 시작하는 것은 어디에서 시작해야하는지 말하기가 번거롭기 때문에 어렵습니다.


어떻게는 두 개의 클래스로 구성, 다음 예제 UI에 대한 최소한의 테스트 설정을 만들 수 있습니까?

제약 : 자바 SE, 스윙 UI, 메이븐 프로젝트, JUnit을

public class MainApp { 

    /** 
    * Run me, to use the app yourself. 
    * 
    * @param args ignored 
    */ 
    public static void main(String[] args) { 
     MainApp.showWindow().setSize(600, 600); 
    } 

    /** 
    * Internal standard method to initialize the view, returning the main JFrame (also to be used in automated tests). 
    * 
    * @return initialized JFrame instance 
    */ 
    public static MainWindow showWindow() { 
     MainWindow mainWindow = new MainWindow(); 
     mainWindow.setVisible(true); 
     return mainWindow; 
    } 
} 

public class MainWindow extends JFrame { 

    public MainWindow() { 
     super("MainWindow"); 
     this.setContentPane(this.createContentPane()); 
    } 

    private JPanel createContentPane() { 
     JTextArea centerArea = new JTextArea(); 
     centerArea.setName("Center-Area"); 
     centerArea.setEditable(false); 
     JButton northButton = this.createButton("North", centerArea); 
     JButton southButton = this.createButton("South", centerArea); 
     JPanel contentPane = new JPanel(new BorderLayout()); 
     contentPane.add(centerArea); 
     contentPane.add(northButton, BorderLayout.NORTH); 
     contentPane.add(southButton, BorderLayout.SOUTH); 
     return contentPane; 
    } 

    private JButton createButton(final String text, final JTextArea centerArea) { 
     JButton button = new JButton(text); 
     button.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent event) { 
       centerArea.setText(centerArea.getText() + text + ", "); 
      } 
     }); 
     return button; 
    } 
} 

내가 그러므로 내가 대답을 제공, 질문 자체가 매우 광범위한 것으로 알고 있어요 나 자신 -이 특정 사례를 보여줍니다.

+1

이 질문에 대한 답변으로이 답변에 대한 의견으로 생성되었습니다. https://stackoverflow.com/a/80222/5127499 – Carsten

답변

1

TL : 예제 프로젝트는 GitHub에 있습니다.


이것은 Maven 프로젝트입니다 가정하면, 먼저 두 개 이상의 종속성을 추가해야합니다 :

  1. 단위 테스트 프레임 워크 (예를 들어 여기 junit을 -뿐만 아니라 testng 사용할 수 있습니다)
  2. 일치 AssertJ Swing 라이브러리 (여기 assertj-swing-junit 예)

그것은 난 볼 수 있었다 이케이 (당신의 pom.xml에 :

/** 
* Base class for all my UI tests taking care of the basic setup. 
*/ 
public class AbstractUiTest extends AssertJSwingTestCaseTemplate { 

    /** 
    * The main entry point for any tests: the wrapped MainWindow. 
    */ 
    protected FrameFixture frame; 

    /** 
    * Installs a {@link FailOnThreadViolationRepaintManager} to catch violations of Swing threading rules. 
    */ 
    @BeforeClass 
    public static final void setUpOnce() { 
     // avoid UI test execution in a headless environment (e.g. when building in CI environment like Jenkins or TravisCI) 
     Assume.assumeFalse("Automated UI Test cannot be executed in headless environment", GraphicsEnvironment.isHeadless()); 
     FailOnThreadViolationRepaintManager.install(); 
    } 

    /** 
    * Sets up this test's fixture, starting from creation of a new <code>{@link Robot}</code>. 
    * 
    * @see #setUpRobot() 
    * @see #onSetUp() 
    */ 
    @Before 
    public final void setUp() { 
     // call provided AssertJSwingTestCaseTemplate.setUpRobot() 
     this.setUpRobot(); 
     // initialize the graphical user interface 
     MainWindow mainWindow = GuiActionRunner.execute(new GuiQuery<MainWindow>() { 

      @Override 
      protected MainWindow executeInEDT() throws Exception { 
       return MainApp.showWindow(); 
      } 
     }); 
     this.frame = new FrameFixture(this.robot(), mainWindow); 
     this.frame.show(); 
     this.frame.resizeTo(new Dimension(600, 600)); 
     onSetUp(); 
    } 

    /** 
    * Subclasses that need to set up their own test fixtures in this method. Called as <strong>last action</strong> during {@link #setUp()}. 
    */ 
    protected void onSetUp() { 
     // default: everything is already set up 
    } 

    /***************************************************************************************** 
    * Here you could insert further helper methods, e.g. frequently used component matchers * 
    *****************************************************************************************/ 

    /** 
    * Cleans up any resources used in this test. After calling <code>{@link #onTearDown()}</code>, this method cleans up resources used by this 
    * test's <code>{@link Robot}</code>. 
    * 
    * @see #cleanUp() 
    * @see #onTearDown() 
    */ 
    @After 
    public final void tearDown() { 
     try { 
      onTearDown(); 
      this.frame = null; 
     } finally { 
      cleanUp(); 
     } 
    } 

    /** 
    * Subclasses that need to clean up resources can do so in this method. Called as <strong>first action</strong> during {@link #tearDown()}. 
    */ 
    protected void onTearDown() { 
     // default: nothing more to tear down 
    } 
} 

실제 테스트 클래스의 모습 수 : 둘째

<dependency> 
    <groupId>junit</groupId> 
    <artifactId>junit</artifactId> 
    <version>4.12</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.assertj</groupId> 
    <artifactId>assertj-swing-junit</artifactId> 
    <version>1.2.0</version> 
    <scope>test</scope> 
</dependency> 

, 나는 보통 실제 테스트에서 테스트 설정의 대부분을 분리하는 하나 개의 기본 테스트 클래스에 갈 다음이 :

public class MainWindowTest extends AbstractUiTest { 

    private JButtonFixture northButtonFixture; 
    private JButtonFixture southButtonFixture; 

    @Override 
    protected void onSetUp() { 
     this.northButtonFixture = this.frame.button(JButtonMatcher.withText("North")); 
     this.southButtonFixture = this.frame.button(JButtonMatcher.withText("South")); 
    } 

    @Test 
    public void testWithDifferingComponentMatchers() { 
     // use JTextComponentMatcher.any() as there is only one text input 
     this.frame.textBox(JTextComponentMatcher.any()).requireVisible().requireEnabled().requireNotEditable().requireEmpty(); 
     this.northButtonFixture.requireVisible().requireEnabled().click(); 
     // use value assigned in MainWindow class via JTextArea.setName("Center-Area") to identify component here 
     this.frame.textBox("Center-Area").requireText("North, "); 

     this.southButtonFixture.requireVisible().requireEnabled().click(); 
     // write our own matcher 
     JTextComponentFixture centerArea = this.frame.textBox(new GenericTypeMatcher(JTextArea.class, true) { 
      @Override 
      protected boolean isMatching(Component component) { 
       return true; 
      } 
     }); 
     centerArea.requireVisible().requireEnabled().requireText("North, South, "); 
    } 

    @Override 
    protected void onTearDown() { 
     this.northButtonFixture = null; 
     this.southButtonFixture = null; 
    } 
} 
프로젝트에서 이러한 기본 설정이 있으면

, 당신은 W 수도 개미는 다양한 종류의 구성 요소 일치자를 조사하기 위해 잠재적으로 몇 가지 setName()을 호출하여 테스트하려는 다양한 구성 요소를 호출하여보다 쉽게 ​​삶을 꾸려 나갈 수 있습니다.

+0

setUp()에서 타사 Java 웹 애플릿을 얻는 방법은 무엇입니까? 벌써 달렸어? –

+0

@StevenVascellaro 어쩌면 AssertJ 스윙 사이트에 대한 설명을 볼 수 있습니다 : http://joel-costigliola.github.io/assertj/assertj-swing-launch.html – Carsten