如何使用Mockito模拟Restriction.eq()

时间:2012-03-20 15:07:57

标签: java hibernate unit-testing mockito powermock

我在使用Mockito创建测试时遇到了一些麻烦。在使用Eclipse进行调试期间,我从null获得Restrictions.eq,我已经完成了为Restrictions创建静态模拟的每一步:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ RequisicaoList.class, StatusMessages.class,
    FacesMessages.class, Restrictions.class })
public class RequisicaoListTest {

...

@SuppressWarnings("unchecked")
public String criteriaContigencia() {
    Criteria criteria = criarCriteria(Requisicao.class);

    criteria.createAlias("produto", "prod");        
    criteria.add(Restrictions.eq("prod.ar",arSelecionada));

    if (getExemplo().getNrProtocolo() != null)
        criteria.add(Restrictions.eq("nrProtocolo", getExemplo()
                .getNrProtocolo()));

    situacoesPesquisa.clear();
    situacoesPesquisa.add(SituacaoRequisicao.PENDENTE_PAGAMENTO);
    situacoesPesquisa.add(SituacaoRequisicao.PENDENTE_AGENDAMENTO);
    if (!situacoesPesquisa.isEmpty()) {
        criteria.add(Restrictions.in("situacao", situacoesPesquisa));
    }   

    if (getExemplo().getResponsavel() != null && StringUtils.isNotBlank(getExemplo().getResponsavel().getCpf())) {
            criteria = criteria.createCriteria("responsavel");
            criteria = criteria.add(Restrictions.eq("cpf", getExemplo().getResponsavel().getCpf()));
    }

    resultado = Collections.checkedList(criteria.list(),Requisicao.class);

    return null;
}

我的代码是将managedBean与持久层混合,我无法改变它,但我必须为该项目创建测试。

这里的问题是模拟

Restrictions.eq("cpf", getExemplo().getResponsavel().getCpf())

因为即便如此:

SimpleExpression simpleExpressionEq = mock(SimpleExpression.class);
PowerMockito.mockStatic(Restrictions.class);
when(Restrictions.eq("cpf", "00000000091")).thenReturn(simpleExpressionEq);

然后我仍然从null返回Restriction.eq,甚至传递了拼写值。但是在调试期间,如果我在表达式视图中做了一个表达式:

Restrictions.eq("cpf", "00000000091"))

它工作正常并返回一个模拟的SimpleExpression

2 个答案:

答案 0 :(得分:2)

我不认为在测试此方法时模拟Restrictions是有意义的。此方法的目的是包装数据访问(Hibernate和您正在使用的任何数据库)。因此,对此方法的有用测试将是确保您正确使用数据库的测试。

因此,我建议编写集成测试,而不是编写一个单元测试,其中一切都是模拟的。使用内存数据库,如H2(http://h2database.com);并编写一个设置适当数据的测试,然后实际选择它。那么,你对这种方法实际做了它应该做的事情的信心水平将远远超过单元测试给你的。

答案 1 :(得分:1)

如果

Restrictions.eq("cpf", "00000000091"))

正确返回,那么问题可能是getExemplo().getResponsavel().getCpf()。你确定它会返回“00000000091”吗?你没有提供足够的代码来判断这是否可能是问题,但是值得研究。

另一种方法是避免完全嘲笑Restrictions。当我想做这样的事情时,我使用真正的Restrictions类并让它返回一个真正的Criterion。我写了一个简单的“toStringEq”匹配器,我可以用来模拟或验证Criteria对象的行为。当然,对象的toString()值的匹配与实际相等的匹配不同,但是由于Criterion对象使用实例相等来进行相等,但是对于具有相同toString()值的Criterion对象在功能上是等价的,我'我发现这个用例很方便。

例如,在您通话后,如果您有一个模拟Criteria对象,则可以:

verify(mockCriteria).add(argThat(toStringEq(Restrictions.eq("cpf", "0000000091"))));

这是简单的匹配器类:

import org.hamcrest.Description;
import org.mockito.ArgumentMatcher;

public class HamcrestToStringMatcher<T> extends ArgumentMatcher<T> {

    private T toMatch;

    public HamcrestToStringMatcher(T toMatch) {
        this.toMatch = toMatch;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(toMatch == null ? "null" : toMatch.toString());
    }

    @Override
    public boolean matches(Object argument) {
        return ((toMatch == null && argument == null) || (toMatch != null
                && argument != null && toMatch.toString().equals(
                argument.toString())));
    }

    public static <T> HamcrestToStringMatcher<T> toStringEq(T toMatch) {
        return new HamcrestToStringMatcher<T>(toMatch);
    }

}