У меня есть тест Mockito, который выглядит примерно так (упрощенно, конечно):
@RunWith(MockitoJUnitRunner.class)
public class BlahTest {
private static final int VERSION = 41;
private static final int PAGE_SIZE = 4096;
@Mock private FileChannel channel;
@Test
public void shouldWriteStandardHeader() throws Exception {
final Blah blah = new Blah(channel, VERSION, PAGE_SIZE);
blah.create();
verify(channel).write(littleEndianByteBufferContaining(Blah.MAGIC_NUMBER,
VERSION,
PAGE_SIZE));
}
private ByteBuffer littleEndianByteBufferContaining(final int... ints) {
return argThat(byteBufferMatcher(ints));
}
private Matcher<ByteBuffer> byteBufferMatcher(final int... ints) {
return new TypeSafeMatcher<ByteBuffer>() {
@Override
public void describeTo(final Description description) {
description.appendText("a little-endian byte buffer containing integers ").
appendValueList("", ",", "", ints);
}
@Override
protected boolean matchesSafely(final ByteBuffer buffer) {
if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {
return false;
}
for (final int i : ints) {
if (buffer.getInt() != i) {
return false;
}
}
return true;
}
};
}
}
По сути, этот тест пытается утверждать, что при вызове Blah.create()
он записывает ByteBuffer
, содержащий определенные данные, в FileChannel
.
Когда я запускаю этот тест, средство вызова вызывается дважды. Это приводит к BufferUnderflowException
.
Теперь я мог бы обойти это, просто сделав, чтобы matcher сохранил позицию буфера в начале вызова matchesSafely
и переместил позицию обратно в нее в конце (в блоке finally), но мне кажется, что мой помощник не должен вызываться дважды.
Может кто-нибудь пролить свет на это?
РЕДАКТИРОВАТЬ # 1:
Вероятно, стоит отметить, что буфер перед переключением на канал переворачивается, поэтому позиция равна 0, а ограничение установлено на количество записанных данных.
Я отладил тест, и определитель вызывается дважды.
Я могу выполнить тестовый прогон, отметив буфер в начале matchesSafely()
и сбросив его в конце, так что второй проход через механизм сопоставления считывает те же данные. Это также подтверждает, что matcher вызывается дважды, так как в противном случае он все равно потерпит неудачу.
РЕДАКТИРОВАТЬ # 2:
Похоже, что это ожидаемое поведение платформы Mockito. Оглядываясь назад, я могу сказать, что мой подход немного беден, потому что он изменяет глобальное состояние. Я изменил механизм сопоставления, чтобы записать начальную позицию и вернуться к ней в конце метода matchesSafely()
. В любом случае, это, вероятно, хорошая идея, поскольку она сохраняет изменяющееся глобальное состояние. Я не использую mark()
и reset()
по той же причине.