Java 将项目添加到购物车时,playframework中的功能测试失败

Java 将项目添加到购物车时,playframework中的功能测试失败,java,testing,playframework,Java,Testing,Playframework,我编写了一个功能测试来检查向购物车添加项目。用户要能够向购物车添加项目,他需要登录。因此,我创建了一个方法来登录用户和另一个方法来添加项目。在测试中的addtocart方法之前和之后,我正在检查购物车内容的大小。当我在开发模式下运行应用程序时,addtocart功能不会出现任何问题(我也可以检查数据库,它是postgres,而不是内存中的数据库)。addtocart在测试中失败 将项目添加到购物车的控制器方法 public static void addItemToCart(Long produ

我编写了一个功能测试来检查向购物车添加项目。用户要能够向购物车添加项目,他需要登录。因此,我创建了一个方法来登录用户和另一个方法来添加项目。在测试中的addtocart方法之前和之后,我正在检查购物车内容的大小。当我在开发模式下运行应用程序时,addtocart功能不会出现任何问题(我也可以检查数据库,它是postgres,而不是内存中的数据库)。addtocart在测试中失败

将项目添加到购物车的控制器方法

public static void addItemToCart(Long productId,Long cartId,String quantity) {
    Product product = Product.findById(productId);
    ShopCart cart = ShopCart.findById(cartId);
    int qty = Integer.parseInt(quantity);
    CartItem cartItem = new CartItem(product,qty);
    cart.addItem(cartItem);
    cart.save();
    System.out.println("Controller::addItemToCart()::cart id="+cart.id+" has="+cart.cartItems.size()+" items);
}
我的测试方法是

 @Test
 public void testUserCanAddItemsToCart() {
    Fixtures.loadModels("data.yml");
    User user = User.find("byEmail","user@shop.com").first();
    loginAsCustomer("user@shop.com","userpass");
    ShopCart usercart = new ShopCart(user);
    usercart.save();
    System.out.println("BEFORE ADD::usercart="+usercart.id+" has :"+usercart.cartItems.size()+" items");
    assertTrue(usercart.cartItems.size()==0);
    addItemsToCart(usercart);
    System.out.println("AFTER ADD::usercart="+usercart.id+" has :"+usercart.cartItems.size()+" items");
    assertFalse(usercart.cartItems.size()==0);//why does this fail?

}  

private Response addItemsToCart(ShopCart cart) {
        Product pdt = Product.find("byIsbn","654-0451160522").first();
        assertNotNull(pdt);
        System.out.println("addItemsToCart():BEFORE ADD cart="+cart.id+" has="+cart.cartItems.size());
        Map<String,String> addtocartParams = new HashMap<String,String>();
        addtocartParams.put("cartId", cart.id.toString());
        addtocartParams.put("quantity", "2");
        String addtocarturl = "/items/addtocart/"+pdt.id.toString();
        Response response = POST(addtocarturl,addtocartParams);
        System.out.println("addItemsToCart():AFTER ADD cart="+cart.id+" has="+cart.cartItems.size());
        return response;
    }
这里,在controller方法中,购物车实例(id=48)保存到db后有1个项目。但在测试方法中,相同id的购物车实例有0个内容

我注释掉了assertFalse方法,并使用cartId从db检索了购物车。即使相同id的购物车也有0个内容。我不明白为什么会发生这种情况。有人能解释一下吗

//试验方法主体..修改

ShopCart cart = ShopCart.findById(usercart.id);
System.out.println("AFTER ADD::cart="+cart.id+" has :"+cart.cartItems.size()+" items");        
assertFalse(cart.cartItems.size()==0);//why does this fail?

它失败是因为测试方法使用的购物车实例与
addItemToCart
方法使用的购物车实例不同。每个事务都有自己的实体实例。当其他事务更新实体映射的行时,JPA不会自动刷新该实体


您应该在调用
addItemsToCart
检查数据库中的购物车是否添加了内容后从数据库重新加载购物车。

我是面向对象思想的奴隶,所以我想知道的是,您是否想过将
addItemsToCart()
作为
购物车
类的方法?我的设想是:

...
ShopCart usercart = new ShopCart(user);
usercart.addItemsToCart(pdt);
usercart.save();

String addtocarturl = "/items/addtocart/"+pdt.id.toString();
Response response = POST(addtocarturl,addtocartParams);
return response;

对我来说,制作(或检索)一个
ShopCart
对象、修改它并将其放入数据库更容易。这就是我如何避免这个问题的。

我也遇到了同样的问题,在从数据库获取模型之前在测试中添加了JPA.em().clear(),为我解决了这个问题。

谢谢你的回答。。我想我在问题的最后一部分尝试过,使用ShopCart.findById(…)。。它仍然返回一个具有相同id但没有内容的实例!是的,但由于您仍然处于同一事务中,所以您是从一级缓存而不是从数据库读取购物车。尝试刷新购物车,或将其从一级缓存中移出并重新加载。或者使用两个不同的事务。谢谢..这就解决了..你给了我很多思考..再次感谢你提出的伟大问题!这将获得从数据库中提取数据的状态性,因此对于其他情况可能非常有用。
...
ShopCart usercart = new ShopCart(user);
usercart.addItemsToCart(pdt);
usercart.save();

String addtocarturl = "/items/addtocart/"+pdt.id.toString();
Response response = POST(addtocarturl,addtocartParams);
return response;