m-namikiの日記

おもしろき こともなき世を おもしろく

Actionのテスト

以下のようなActionクラスに対して、jUnitテストを行う方法を模索中。

public class EmployeeAction {
    @ActionForm
    @Resource
    public EmployeeForm employeeForm;
    @Resource
    public EmployeeService employeeService;
    public List<Employee> empItems;
    @Execute(validator=false)    
    public String index() {
        empItems = employeeService.findAll();
        return "index.jsp";
    }
}

これに対するテストクラス。ActionでServiceを呼び出している部分はMockInterceptorで置き換える。

public class TestEmployeeAction extends S2TestCase {
    private EmployeeAction employeeAction;
    private MockInterceptor employeeServiceMI;
    protected void setUp() throws Exception {
        include("TestEmployeeAction.dicon");
        employeeAction = new EmployeeAction();
    }
    public void testIndex() throws Exception {
        employeeServiceMI.setReturnValue(new ArrayList<Employee>());
        ssertEquals("index.jsp", employeeAction.index());
        employeeServiceMI.isInvoked("findAll");
    }
}

最後にテストクラスで読み込んでいるdiconファイル。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
  "http://www.seasar.org/dtd/components24.dtd">
<components>
  <component name="employeeServiceMI" class="org.seasar.framework.aop.interceptors.MockInterceptor"/>
  <component name="employeeService" class="com.example.service.EmployeeService">
    <aspect>employeeServiceMI</aspect>
  </component>
</components>

以前Cubbyのテストクラスを作ったときにはこんな感じの方法で上手く動いてたので大丈夫だろうと思っていたのだが、いざ実際に実行してみたら、以下のようなエラーが発生してしまった。

org.seasar.framework.container.IllegalAutoBindingPropertyRuntimeException: [ESSR0080]クラス(com.example.service.EmployeeService$$EnhancedByS2AOP$$fe256b)のプロパティ(jdbcManager)の自動設定に失敗しました
	at org.seasar.framework.container.assembler.BindingTypeMustDef.doBind(BindingTypeMustDef.java:46)
	at org.seasar.framework.container.assembler.AbstractBindingTypeDef.bind(AbstractBindingTypeDef.java:91)
	at org.seasar.framework.container.assembler.AccessTypeFieldDef.bind(AccessTypeFieldDef.java:50)
	at org.seasar.framework.container.assembler.AccessTypeFieldDef.bind(AccessTypeFieldDef.java:42)
	at org.seasar.framework.container.assembler.AutoPropertyAssembler.assemble(AutoPropertyAssembler.java:56)
	at org.seasar.framework.container.deployer.SingletonComponentDeployer.assemble(SingletonComponentDeployer.java:68)
	at org.seasar.framework.container.deployer.SingletonComponentDeployer.deploy(SingletonComponentDeployer.java:48)
	at org.seasar.framework.container.deployer.SingletonComponentDeployer.init(SingletonComponentDeployer.java:76)
	at org.seasar.framework.container.impl.ComponentDefImpl.init(ComponentDefImpl.java:236)
	at org.seasar.framework.container.impl.S2ContainerImpl.init(S2ContainerImpl.java:563)
	at org.seasar.framework.container.impl.ThreadSafeS2ContainerImpl.init(ThreadSafeS2ContainerImpl.java:172)
	at org.seasar.framework.container.impl.S2ContainerImpl.init(S2ContainerImpl.java:560)
	at org.seasar.framework.unit.S2FrameworkTestCase.runBare(S2FrameworkTestCase.java:300)
	at junit.framework.TestResult$1.protect(TestResult.java:110)
	at junit.framework.TestResult.runProtected(TestResult.java:128)
	at junit.framework.TestResult.run(TestResult.java:113)
	at junit.framework.TestCase.run(TestCase.java:124)
	at junit.framework.TestSuite.runTest(TestSuite.java:232)
	at junit.framework.TestSuite.run(TestSuite.java:227)
	at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

ちなみにEmployeeServcieはこんな感じ。チュートリアルと同様に中身は空っぽ。

public class EmployeeService extends S2AbstractService<Employee> {
}

TestEmployeeActionを以下のように書き換えると正常にテスト出来るが、MockInterceptor#createProxy()を使うのがなんだか違う気がしてしょうがない。ここら辺はコンテナが設定してくれるように出来ると思うんだけどなぁ。

public class TestEmployeeAction extends S2TestCase {
    private EmployeeAction employeeAction;
    private MockInterceptor employeeServiceMI;
    protected void setUp() throws Exception {
// diconの読み込みをコメントアウト
//        include("TestEmployeeAction.dicon");
        employeeAction = new EmployeeAction();
    }
    public void testIndex() throws Exception {
        employeeServiceMI = new MockInterceptor();
        employeeServiceMI.setReturnValue(new ArrayList<Employee>());
// Actionのプロパティに設定
        employeeAction.employeeService = (EmployeeService) employeeServiceMI.
                createProxy(EmployeeService.class);
        ssertEquals("index.jsp", employeeAction.index());
        employeeServiceMI.isInvoked("findAll");
    }
}

うーん、そもそもテストの方法が間違っているんだろうか。。。