1

我有以下情况。我想将设置创建日期的责任委托给 DAO 对象。

    Class Product{
     //other fields
     Date creationDate;
    }

    Class ProductDAO{
      private GenericDAO dao;
      public void create(Product p){
         p.setCreationDate(new Date());
         dao.create(p);
      }
    }

    Class Main{
      private ProductDAO productDAO; 
      public void createProduct(){
         Product p = new Product();
         productDAO.create(p);
         LOG.debug(p.getCreationDate());
      } 
    }
  1. 现在的问题是,当我通过模拟 productDAO 测试主类的 createProduct 方法时,如何定义模拟对象“productDAO”的行为,以便它设置创建日期并且日志语句不会抛出 NullPointerException?
  2. 上述方法似乎正确吗?我应该从 ProductDAO 类的 create 方法返回更新的 Product 对象而不是依赖副作用吗?

     Product create(Product p){
           p.setCreationDate(new Date());
           dao.create(p);
           return p;
      }
    
  3. 或者在主类中,我应该在创建后从数据库中读取对象,而不是依赖于返回对象或 createProduct 方法的副作用?在这种情况下,唯一的事情是它会增加额外调用的开销。

     public void createProduct(){
         Product p = new Product();
         productDAO.create(p);
         p = productDAO.read(p.getId());
         LOG.debug(p.getCreationDate());
      } 
    

对不起,很长的问题。我希望我能够解释。

4

3 回答 3

2

测试日期是否已设置的一种方法是使用argThat。你需要做类似的事情

@Test
public void shouldSetCreationDateAtProductWhenCreatingIt() {
     // given
     Product product = mock(Product.class);

     // when
     dao.create(product);

     // then
     verify(product).setCreationDate(argThat(is(not(nullValue(Date.class)))));
}

所以,我只做了一个简单的验证,Product#setCreationDate(Date)它使用非空值调用Date。您可以创建自定义匹配器以查看Date对象是否是您期望的对象。这是只测试类ProductDao

如果您想以Main需要模拟 getCreationDate 的返回的方式进行单元测试,您可以向您的 中添加一个返回ProductDao#create,使其返回持久对象。

 public class ProductDao {
     public Product create(Product p){
        p.setCreationDate(new Date());
        dao.create(p);
        return p;
     }
 }

然后你可以在你的 Main 类中模拟 productDao 的返回

  @Test
  public void shouldUseReturnedProductFromDaoToLog() {
       // given
       Product product = mock(Product.class);
       Date creationDate = new Date();

       given(product.getCreationDate()).willReturn(creationDate);
       given(dao.create(any(Product.class)).willReturn(product);

       // when      
       Product createdProduct = main.createProduct();

       // then
       assertThat(createdProduct, is(equalTo(product)));
  }

我在 createProduct 中添加了一个返回,因为我想测试它是否与 DAO 返回的相同。然后,我们将单元测试从(创建产品并将其持久化到 Dao)中分离出来,看看是否ProductDao符合预期(设置创建日期)Main

希望这可以帮助。

于 2013-02-21T21:45:04.357 回答
1
  1. I think a perfectly valid approach would be to make an instance of Product which has a creationDate "set" and have your mockProductDao return that.

    Date timeStamp = new Date();
    Product productWithCreationDate = new Product();
    productWithCreationDate.setCreationDate(timeStamp);
    when(mockProductDao.create(anyObject()).thenReturn(productWithCreationDate);
    
  2. I don't think you need to return p from your ProductDAO, since any place you call productDAO.create(p), then you have access to p (with creationDate) on the very next line - right?

  3. You only need to read p back from the DAO if you don't trust the DAO layer :) So, given that you are confident the DAO layer will throw the correct exception if create() method fails, I don't think you need to re-read p again.

于 2013-02-21T21:39:48.657 回答
0

为什么需要Date通过 setter 分配创建?只需分配Datein 构造函数:

Product p = new Product();  //here you set creation date
productDAO.create(p);  
于 2013-02-21T21:42:26.893 回答