Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Locked History Actions

wicket/ExWicketTester

拡張Wicketテスタ

ここでは、Wicketに標準で備わっているひどいテスタの代わりに、タイプセーフでリファクタリングに強い代替のテスタを提案してみる。

ひどいWicketプログラムとそのテスト

ひどいとは言っても、ごく普通に書くとこうなる。

<html>
<title>Login</title>
<body>
<div wicket:id="feedback"></div>
<form wicket:id="loginForm">
<table border="0">
 <tr><td>メールアドレス</td><td><input type="text" wicket:id="email"/></td></tr>
 <tr><td>パスワード</td><td><input type="password" wicket:id="pass"/></td></tr>
 <tr align="right"><td colspan="2"><input type="submit" value="ログイン"/></td></tr>
</table>
</form>
</body>
</html>

import org.apache.wicket.markup.html.*;
import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.markup.html.panel.*;
import org.apache.wicket.model.*;

public class LoginPage extends WebPage {
  
  public LoginPage() {    
    add(new FeedbackPanel("feedback"));
    add(new LoginForm());
  }
  
  class LoginForm extends Form<Void> {    
    
    private LoginForm() {
      super("loginForm");
      add(new TextField<String>("email", new Model<String>()));
      add(new PasswordTextField("pass", new Model<String>()));
    }    
    
    @Override
    public void onSubmit() {
      String mail = get("email").getDefaultModelObjectAsString();
      String pass = get("pass").getDefaultModelObjectAsString();
      
      // login success or failed ....     
    }
  }
}

import org.apache.wicket.util.tester.*;
import org.junit.*;

public class LoginTest {

  @Test
  public void test() {
    WicketTester tester = new WicketTester();
    tester.startPage(LoginPage.class);
    tester.assertRenderedPage(LoginPage.class);
    tester.assertNoErrorMessage();
    
    FormTester formTester = tester.newFormTester("loginForm");
    formTester.setValue("email", "sysdba");
    formTester.setValue("pass", "masterkey");
    formTester.submit();
    tester.assertNoErrorMessage();
    
  }
}

LoginPageの改良

少なくともLoginPageクラスは以下のようにし、文字列ではなく文字列定数を参照すべきだろう。

import org.apache.wicket.markup.html.*;
import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.markup.html.panel.*;
import org.apache.wicket.model.*;

public class LoginPage extends WebPage {
  
  static final String ID_FEEDBACK = "feedback";
  static final String ID_LOGINFORM = "loginForm";
  static final String ID_EMAIL = "email";
  static final String ID_PASS = "pass";
  
  public LoginPage() {    
    add(new FeedbackPanel(ID_FEEDBACK));
    add(new LoginForm());
  }
  
  class LoginForm extends Form<Void> {    
    
    private LoginForm() {
      super(ID_LOGINFORM);
      add(new TextField<String>(ID_EMAIL, new Model<String>()));
      add(new PasswordTextField(ID_PASS, new Model<String>()));
    }    
    
    @Override
    public void onSubmit() {
      String mail = get(ID_EMAIL).getDefaultModelObjectAsString();
      String pass = get(ID_PASS).getDefaultModelObjectAsString();
      
      // login success or failed ....     
    }
  }
}

さらにLoginPageTestも以下のように、その文字列定数を参照させる。

import org.apache.wicket.util.tester.*;
import org.junit.*;
import static test.LoginPage.*;

public class LoginTest {

  @Test
  public void test() {
    WicketTester tester = new WicketTester();
    tester.startPage(LoginPage.class);
    tester.assertRenderedPage(LoginPage.class);
    tester.assertNoErrorMessage();
    
    FormTester formTester = tester.newFormTester(ID_LOGINFORM);
    formTester.setValue(ID_EMAIL, "sysdba");
    formTester.setValue(ID_PASS, "masterkey");
    formTester.submit();
    tester.assertNoErrorMessage();
    
  }
}

本当はこのようにしたい

LoginPage側では、テストで参照されるであろうコンポーネントをフィールドとして保持しておく。 これは問題ない。

import org.apache.wicket.markup.html.*;
import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.markup.html.panel.*;
import org.apache.wicket.model.*;

public class LoginPage extends WebPage {
  
  static final String ID_FEEDBACK = "feedback";
  static final String ID_LOGINFORM = "loginForm";
  static final String ID_EMAIL = "email";
  static final String ID_PASS = "pass";
  
  LoginForm loginForm;
  
  public LoginPage() {    
    add(new FeedbackPanel(ID_FEEDBACK));
    add(loginForm = new LoginForm());
  }
  
  class LoginForm extends Form<Void> {    
    
    TextField<String>emailField;
    PasswordTextField passField;
    
    private LoginForm() {
      super(ID_LOGINFORM);
      add(emailField = new TextField<String>(ID_EMAIL, new Model<String>()));
      add(passField = new PasswordTextField(ID_PASS, new Model<String>()));
    }    
    
    @Override
    public void onSubmit() {
      String mail = emailField.getDefaultModelObjectAsString();
      String pass = passField.getDefaultModelObjectAsString();
      
      // login success or failed ....     
    }
  }
}

テストの方は以下のようにしたい。ID文字列は一切使わず、コンポーネントのみを参照する。 これはWicket付属のテスターではできない。

public class LoginTest {

  @Test
  public void test() {
    WicketTester tester = new WicketTester();
    tester.startPage(LoginPage.class);
    tester.assertRenderedPage(LoginPage.class);
    tester.assertNoErrorMessage();
    
    LoginPage loginPage = tester.getLastRenderedPage();
    LoginForm loginForm = loginPage.loginForm;  
    
    FormTester formTester = tester.newFormTester(loginForm);
    formTester.setValue(loginForm.emailField, "sysdba");
    formTester.setValue(loginForm.passField, "masterkey");
    formTester.submit();
    tester.assertNoErrorMessage();
    
  }
}

拡張Wicketテスタ

ということで、ソースはこちらこれを使うとテストユニットは次のように書ける。

import org.junit.*;

import test.LoginPage.*;

import com.cm55.third.wicket.test.*;

public class LoginTest {

  @Test
  public void test() {
    ExWicketTester tester = new ExWicketTester();
    LoginPage loginPage = tester.startPage(LoginPage.class);
    tester.assertRenderedPage(LoginPage.class);
    tester.assertNoErrorMessage();
    
    LoginForm loginForm = loginPage.loginForm;    
    ExFormTester<LoginForm> formTester = tester.newFormTester(loginForm);
    formTester.setValue(loginForm.emailField, "sysdba");
    formTester.setValue(loginForm.passField, "masterkey");
    formTester.submit();
    tester.assertNoErrorMessage();    
  }
}