从DAO中的create方法返回对象

时间:2013-02-21 21:30:31

标签: java

我有以下情况。我想将设置创建日期的责任委托给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. 现在的问题是,当我测试主类的createProduct方法时 mocking productDAO,如何定义模拟对象的行为 'productDAO',以便它设置创建日期和日志语句 不会抛出NullPointerException?
  2. 上述方法似乎正确吗?我应该退回更新的产品吗? 来自ProductDAO类的create方法而不是依赖的对象 副作用?

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

     public void createProduct(){
         Product p = new Product();
         productDAO.create(p);
         p = productDAO.read(p.getId());
         LOG.debug(p.getCreationDate());
      } 
    
  4. 很抱歉。我希望我能解释一下。

3 个答案:

答案 0 :(得分:1)

  1. 我认为一个非常有效的方法是创建一个具有creationDate“set”的Product实例,并让你的mockProductDao返回。

    Date timeStamp = new Date();
    Product productWithCreationDate = new Product();
    productWithCreationDate.setCreationDate(timeStamp);
    when(mockProductDao.create(anyObject()).thenReturn(productWithCreationDate);
    
  2. 我认为您不需要从ProductDAO返回p,因为您调用productDAO.create(p)的任何地方,然后您可以在下一个地方访问p(with creationDate) line - 对吗?

  3. 如果你不信任DAO层,你只需要从DAO读回p :)所以,鉴于你确信DAO层会抛出正确的异常{{1 }}方法失败,我认为您不需要再次重新阅读create()

答案 1 :(得分:1)

测试日期是否设置的一种方法是使用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

如果要以模拟getCreationDate返回的方式对单元测试Main进行单元测试,可以向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返回的相同。然后我们将单元测试分开,看看ProductDao是否从Main做了预期(设置creationDate)(创建产品并将其保存在Dao中)

希望这有帮助。

答案 2 :(得分:0)

为什么需要通过setter分配创建Date?只需在构造函数中指定Date

Product p = new Product();  //here you set creation date
productDAO.create(p);