The
Struts 2 Action doesn't expose HTTP in its signature. When access to
HTTP resources is needed, references to these resources can be injected
at runtime, but, to the Action, the servlet resources appear as
ordinary Maps. When running tests outside of the framework, the test
scaffolding can create and set a Map with whatever objects are needed
by the test.
Struts2 Action在簽名上不依賴預HTTP。當訪問需要的HTTP是,這些資源在運行時能構被注入。Action,servlet資源看上區就像通用的Maps。當在Framework外部測試時,測試平臺會建立所有需要的任何對象的映射。
There are several approaches to unit testing Struts 2-based applications, whether using JUnit
or TestNG
.
Two popular techniques are direct Action invocation and testing
interceptors and result-types independently. We will demonstrate both
approaches using JUnit 3.
兩個流行的技術是獨立地測試直接的Action調用和interceptor和Result-Type。
Direct Action Invocation
The simplest approach is to instantiate your Actions, call the appropriate setters, then invoke execute. Calling the Action directly allows you to bypass all the complicated container setup.
最簡單的手段是實例化Action,調用相關的Setter,然后調用excute。調用Action直接允許你繞過復雜的容器啟動過程。
package org.petsoar.actions.inventory;
import com.mockobjects.constraint.IsEqual;
import com.mockobjects.dynamic.C;
import com.mockobjects.dynamic.Mock;
import com.opensymphony.xwork.Action;
import junit.framework.TestCase;
import org.petsoar.pets.Pet;
import org.petsoar.pets.PetStore;
public class TestViewPet extends TestCase {
private Mock mockPetStore;
private ViewPet action;
protected void setUp() throws Exception {
mockPetStore = new Mock(PetStore.class);
PetStore petStore = (PetStore) mockPetStore.proxy();
action = new ViewPet();
action.setPetStore(petStore);
}
public void testViewPet() throws Exception {
Pet existingPet = new Pet();
existingPet.setName("harry");
existingPet.setId(1);
Pet expectedPet = new Pet();
expectedPet.setName("harry");
expectedPet.setId(1);
mockPetStore.expectAndReturn("getPet", C.args(new IsEqual(new Long(1))), existingPet);
action.setId(1);
String result = action.execute();
assertEquals(Action.SUCCESS, result);
assertEquals(expectedPet, existingPet);
mockPetStore.verify();
}
public void testViewPetNoId() throws Exception {
mockPetStore.expectAndReturn("getPet", C.ANY_ARGS, null);
String result = action.execute();
assertEquals(Action.ERROR, result);
assertEquals(1, action.getActionErrors().size());
assertEquals("Invalid pet selected.", action.getActionErrors().iterator().next());
assertNull(action.getPet());
mockPetStore.verify();
}
public void testViewPetInvalidId() throws Exception {
action.setId(-1);
testViewPetNoId();
}
}
Testing Interceptors and/or Result Types
Check out the test suites in XWork and Struts 2. These suites are
comprehensive and provide a good starting point. Here's an example.
取出XWork和Struts2的測試套件,這些測試套件是復雜的,并且提供了好的起點。
public void testDoesNotAllowMethodInvocations() {
Map params = new HashMap();
params.put("@java.lang.System@exit(1).dummy", "dumb value");
HashMap extraContext = new HashMap();
extraContext.put(ActionContext.PARAMETERS, params);
try {
ActionProxy proxy = ActionProxyFactory.getFactory().
createActionProxy("", MockConfigurationProvider.MODEL_DRIVEN_PARAM_TEST, extraContext);
assertEquals(Action.SUCCESS, proxy.execute());
ModelDrivenAction action = (ModelDrivenAction) proxy.getAction();
TestBean model = (TestBean) action.getModel();
String property = System.getProperty("action.security.test");
assertNull(property);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
The framework also provides built-in support for JUnit 3.8 via an
abstract StrutsTestCase, which provides common Struts variables and
setup code.
框架也提供了一個抽象的StrutsTestCase,支持JUnit3.8,這個類提供了常用的Struts變量和啟動代碼。