如何使用mockito更改调用历史



注意:mockito 1.10.19

场景如下:;我有一个抽象类:

/**
 *
 * @param <M> metadata class
 */
@ParametersAreNonnullByDefault
public abstract class AttributeWriter<M>
    implements AttributeWriterByName
{
    protected final MetadataDriver<M> driver;
    protected final Path path;
    protected AttributeWriter(final Path path, final MetadataDriver<M> driver)
    {
        this.driver = driver;
        this.path = path;
    }
}

AttributeWriterByName接口非常简单:

@ParametersAreNonnullByDefault
public interface AttributeWriterByName
{
    void setAttributeByName(String name, Object value)
        throws IOException;
}

一个实现的例子是(最简单的):

@SuppressWarnings("DesignForExtension")
@ParametersAreNonnullByDefault
public abstract class FileOwnerAttributeWriter<M>
    extends AttributeWriter<M>
{
    protected FileOwnerAttributeWriter(final Path path,
        final MetadataDriver<M> driver)
    {
        super(path, driver);
    }
    @Override
    public void setAttributeByName(final String name, final Object value)
        throws IOException
    {
        if (!"owner".equals(Objects.requireNonNull(name)))
            throw new NoSuchAttributeException(name);
        setOwner((UserPrincipal) Objects.requireNonNull(value));
    }
    @SuppressWarnings("MethodMayBeStatic")
    public void setOwner(final UserPrincipal owner)
        throws IOException
    {
        throw new ReadOnlyAttributeException();
    }
}

匹配的测试文件依赖于一个抽象类,该类如下所示:

public abstract class AttributeWriterTest<W extends AttributeWriter<Object>>
{
    protected final Path path = mock(Path.class);
    @SuppressWarnings("unchecked")
    protected MetadataDriver<Object> driver = mock(MetadataDriver.class);
    protected W writer;
    protected static FileTime nullFileTime()
    {
        return isNull(FileTime.class);
    }
    @BeforeMethod
    public abstract void init()
        throws IOException;
}

至于实际的测试类,它是:

public final class FileOwnerAttributeWriterTest
    extends AttributeWriterTest<FileOwnerAttributeWriter<Object>>
{
    @BeforeMethod
    @Override
    public void init()
        throws IOException
    {
        writer = spy(new FileOwnerAttributeWriter<Object>(path, driver)
        {
        });
        doNothing().when(writer).setOwner(any(UserPrincipal.class));
    }
    @Test
    public void setOwnerTest()
        throws IOException
    {
        final UserPrincipal owner = mock(UserPrincipal.class);
        writer.setAttributeByName("owner", owner);
        verify(writer).setOwner(same(owner));
    }
}

现在,我遇到的问题如下:我基本上想检查在调用.setAttributeName()之后,除了.setOwner()之外,没有其他事情发生。

但是,如果我添加到我想要verifyNoMoreInteractions(writer)的测试中,这将失败,因为在同一测试中,我调用.setAttributeByName()。。。

尽管这很可能是我的设计中的一个问题(我仍在试验),但有没有一种方法可以让mockito在这样的测试中忽略对setAttributeByName()的调用,这样我就可以写这个了?

verify(writer, only()).setOwner(same(owner));

EDIT我想写的东西,或者如果它已经存在的话,是这样的:

@Test
public void setOwnerTest()
    throws IOException
{
    final UserPrincipal owner = mock(UserPrincipal.class);
    ignoreInvocation(writer).setAttributeByName("owner", owner);
    verify(writer, only()).setOwner(same(owner));
}

我找到了一种方法,请参阅下面的简化示例。总之,您可以在触发对real方法的调用之前重置mock。

我回答这个问题是为了练习Mockito,但我希望很明显,你几乎肯定不应该这样做。

public class SimplifiedExample {
  class ClassUnderTest {
    public void doSomething(String value) {
      doSomethingElse(value);
    }
    public void doSomethingElse(String value) {
      System.out.println(value);
    }
  }
  @Test
  public void testMethod() throws Exception {
    ClassUnderTest foo = spy(new ClassUnderTest());    
    final String input = "bar";
    doAnswer(new Answer<Void>() {
      @Override
      public Void answer(InvocationOnMock invocation) throws Throwable {
        reset(foo);
        invocation.callRealMethod();
        return null;
      }
    }).when(foo).doSomething(anyString());
    foo.doSomething(input);
    verify(foo, only()).doSomethingElse(input);
  }
}

相关内容

  • 没有找到相关文章

最新更新