### Question:
SyncProcessor implements SyncEventsHandler { @Override public boolean sendBlockHashRequest(long height) { logger.trace("Send hash request to node {} height {}", selectedPeerId, height); BlockHashRequestMessage message = new BlockHashRequestMessage(++lastRequestId, height); return sendMessage(selectedPeerId, message); } SyncProcessor(Blockchain blockchain,
                         BlockSyncService blockSyncService,
                         PeerScoringManager peerScoringManager,
                         ChannelManager channelManager,
                         SyncConfiguration syncConfiguration,
                         BlockHeaderValidationRule blockHeaderValidationRule,
                         DifficultyCalculator difficultyCalculator); void processStatus(MessageChannel sender, Status status); void processSkeletonResponse(MessageChannel peer, SkeletonResponseMessage message); void processBlockHashResponse(MessageChannel peer, BlockHashResponseMessage message); void processBlockHeadersResponse(MessageChannel peer, BlockHeadersResponseMessage message); void processBodyResponse(MessageChannel peer, BodyResponseMessage message); void processNewBlockHash(MessageChannel peer, NewBlockHashMessage message); void processBlockResponse(MessageChannel peer, BlockResponseMessage message); @Override boolean sendSkeletonRequest(NodeID nodeID, long height); @Override boolean sendBlockHashRequest(long height); @Override boolean sendBlockHeadersRequest(ChunkDescriptor chunk); @Override Long sendBodyRequest(@Nonnull BlockHeader header, NodeID peerId); Set<NodeID> getKnownPeersNodeIDs(); void onTimePassed(Duration timePassed); @Override void startSyncing(NodeID nodeID); @Override void startDownloadingBodies(List<Deque<BlockHeader>> pendingHeaders, Map<NodeID, List<BlockIdentifier>> skeletons); @Override void startDownloadingHeaders(Map<NodeID, List<BlockIdentifier>> skeletons, long connectionPoint); @Override void startDownloadingSkeleton(long connectionPoint); @Override void startFindingConnectionPoint(); @Override void stopSyncing(); @Override void onErrorSyncing(String message, EventType eventType, Object... arguments); @Override void onSyncIssue(String message, Object... arguments); @Override void onCompletedSyncing(); @VisibleForTesting void registerExpectedMessage(MessageWithId message); @VisibleForTesting void setSelectedPeer(MessageChannel peer, Status status, long height); @VisibleForTesting SyncState getSyncState(); @VisibleForTesting boolean isPeerSyncing(NodeID nodeID); @VisibleForTesting Map<Long, MessageType> getExpectedResponses();  }### Answer:
@Test public void sendBlockHashRequest() { Blockchain blockchain = BlockChainBuilder.ofSize(0); SimpleMessageChannel sender = new SimpleMessageChannel(new byte[] { 0x01 }); final ChannelManager channelManager = mock(ChannelManager.class); Channel channel = mock(Channel.class); when(channel.getNodeId()).thenReturn(sender.getPeerNodeID()); when(channelManager.getActivePeers()).thenReturn(Collections.singletonList(channel)); final Message[] msg = new Message[1]; when(channelManager.sendMessageTo(eq(sender.getPeerNodeID()), any())).then((InvocationOnMock invocation) -> { msg[0] = invocation.getArgumentAt(1, Message.class); return true; }); SyncProcessor processor = new SyncProcessor(blockchain, null, UscMockFactory.getPeerScoringManager(), channelManager, SyncConfiguration.IMMEDIATE_FOR_TESTING, new ProofOfWorkRule(config).setFallbackMiningEnabled(false), DIFFICULTY_CALCULATOR); processor.setSelectedPeer(sender, StatusUtils.getFakeStatus(), 0); Assert.assertFalse(processor.isPeerSyncing(sender.getPeerNodeID())); processor.sendBlockHashRequest(100); Message message = msg[0]; Assert.assertNotNull(message); Assert.assertEquals(MessageType.BLOCK_HASH_REQUEST_MESSAGE, message.getMessageType()); BlockHashRequestMessage request = (BlockHashRequestMessage)message; Assert.assertNotEquals(0, request.getId()); Assert.assertEquals(100, request.getHeight()); Assert.assertEquals(1, processor.getExpectedResponses().size()); }