问题
While writing FunctionalTest for a webapp based on play1.2.4,I was a little confused as to how to code it properly.The confusion is regarding the transaction boundary involved.I read somewhere that each test has its own transaction.
In my app,a User can login and add some items to the cart.Then he can give an Address sothat the items can be sent to him.
I created private helper methods like below
private Cart buyItemsAsCustomer(String email,String pass) {
User user = User.find("byEmail", email).first();
//login
Response loginResponse = loginAsUser(email,pass);
Cart cart = new Cart(user);
cart.save();
addItemsToCart(cart.id);
return cart;
}
private Response loginAsUser(String email,String password) {
Map<String,String> loginUserParams = new HashMap<String,String>();
loginUserParams.put("username", email);
loginUserParams.put("password", password);
Response response = POST("/login",loginUserParams);
return response;
}
private Response addItemsToCart(Long cartId) {
Cart cart = Cart.findById(cartId);
Item item = Item.find("byIsbn","978-0451160522").first();
Map<String,String> addtocartParams = new HashMap<String,String>();
addtocartParams.put("cartId", cart.id.toString());
addtocartParams.put("quantity", "2");
String addtocarturl = "/items/addtocart/"+item.id.toString();
Response response = POST(addtocarturl,addtocartParams);
cart.refresh();//without this the assertion about number of items in cart fails!
return response;
}
private Map<String,String> createAddressParams(){
Map<String,String> addressParams = new HashMap<String,String>();
addressParams.put("addressline1", "1123,xx street");
addressParams.put("state", "new york");
addressParams.put("country", "US");
return addressParams;
}
Finally I wrote the FunctionalTest which calls each of these helper methods to do the tasks and then does the assertions
@Test
public void testCustomerCanAddAddress() {
Fixtures.loadModels("data.yml");
assertTrue(Address.findAll().size()==0);
Cart joncart = buyItemsAsCustomer("jon@gmail.com","jon");
assertFalse(jonart.cartItems.size()==0);
Map<String,String> addressParams = createAddressParams();
POST("/items/address/"+joncart.customer.getId().toString(),addressParams);
assertTrue(Address.findAll().size()==1);
}
Running this produces a
A java.lang.RuntimeException has been caught, java.util.concurrent.ExecutionException: play.exceptions.JavaExecutionException
at
POST("/items/address/"+joncart.customer.getId().toString(),addressParams);
I think this happens because of some transaction boundary issue ,but I am not sure..Can someone please help me correct this?..I really would like some help as to how the test should be written in this case..
I have pasted the stacktrace here
回答1:
Your test are weird because you mix http calls and models calls. A functional test is purely http calls. You test your controllers layer
If you need some mock data you have to create them in another transaction, the easyest way to do that for me is to use a job in specific method. Same thing if you want to retrieve data to ensure your test passed.
@Before
public void cleanUp() throws Exception {
new Job() {
@Override
public void doJob() throws Exception {
Fixtures.deleteDatabase();
Fixtures.loadModels("data.yml");
}
}.now().get();
}
回答2:
The java.util.concurrent.ExecutionException is not necessarily caused by transactions. I got this exception for my functional test because I had not specified a proper POST route for my controller method in routes file.
However, if I need to use POST requests that modify the database and I need to check the result in the functional test method, I use
Response response = POST("address/to/my/controller/", params);
JPAPlugin.closeTx(false);
JPAPlugin.startTx(false);
// Check here that the changes to the database are correct!
来源:https://stackoverflow.com/questions/9510762/proper-way-of-writing-functionaltest-in-playframework