模拟加载导航属性

时间:2016-01-22 13:20:05

标签: java unit-testing mockito

这是我的代码的一个非常简化的版本,它说明了具体的问题。

有什么方法可以控制从测试中调用accountProductRepository.refresh()时会发生什么?

不知何故,我需要在buyProduct()方法中创建的AccountProductPojo上设置ProductPojo,因此在访问getProduct()。getName()属性时,我不会得到空指针。

refresh使用javax.persistence.EntityManager.refresh()根据buyProduct()方法中设置的id加载导航属性。

public class ProductServiceTest {
    @InjectMocks
    IProductService productService = new ProductService();
    @Mock
    IWriteANoteService writeANoteService;
    @Mock
    IAccountProductRepository accountProductRepository;

    @Test
    public void buyProductTest() {
        productService.buyProduct(1l, 1l);
    }
}

@Service
public class ProductService implements IProductService {
    @Autowired
    IWriteANoteService writeANoteService;

    @Autowired
    IAccountProductRepository accountProductRepository:

    public void buyProduct(Long productId, Long accountId) {
        AccountProductPojo accountProduct = new AccountProductPojo();
        accountProduct.setProductId(productId);
        accountProduct.setAccountId(accountId);

        accountProductRepository.persist(accountProduct);
        // load navigation properties
        accountProductRepository.refresh(accountProduct);

        writeANoteService.writeAccountNote(accountId, "Bought product " + accountProduct.getProduct().getName());
    }
}

@Entity
@Table(name = "account_product")
public class AccountProductPojo {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "account_id")
    private Long accountId;

    @Column(name = "product_id")
    private Integer productId;

    @ManyToOne
    @JoinColumn(name = "product_id", insertable = false, updatable = false)
    private ProductPojo product;

    @OneToOne(fetch = FetchType.LAZY, targetEntity = AccountPojo.class)
    @JoinColumn(name = "account_id", insertable = false, updatable = false)
    private AccountPojo account;

    // getters and setters
}

1 个答案:

答案 0 :(得分:2)

这似乎是mocking a void method的一个相当经典的案例。

您可以尝试这样的事情:

    Mockito.doAnswer(new Answer() {
          public Object answer(InvocationOnMock invocation) {
              Object[] args = invocation.getArguments();
              AccountProductPojo accountProduct = (AccountProductPojo) args[0];
              accountProduct.setProduct(new ProductPojo(PRODUCT_ID_CONSTANT, PRODUCT_NAME_CONSTANT));
              return null;
          }}).when(accountProductRepository).refresh(Mockito.any());

这里的关键是当在模拟上调用refresh()时,你在POJO上调用setProduct(),它作为refresh()调用的参数传递,以避免后来的null指针异常。