### Question:
SyncLearning extends Learning<OBSERVATION, ACTION, ACTION_SPACE, NN> implements IEpochTrainer { public void train() { log.info("training starting."); boolean canContinue = listeners.notifyTrainingStarted(); if (canContinue) { while (this.getStepCount() < getConfiguration().getMaxStep()) { preEpoch(); canContinue = listeners.notifyNewEpoch(this); if (!canContinue) { break; } IDataManager.StatEntry statEntry = trainEpoch(); canContinue = listeners.notifyEpochTrainingResult(this, statEntry); if (!canContinue) { break; } postEpoch(); if(getEpochCount() % progressMonitorFrequency == 0) { canContinue = listeners.notifyTrainingProgress(this); if (!canContinue) { break; } } log.info("Epoch: " + getEpochCount() + ", reward: " + statEntry.getReward()); incrementEpoch(); } } listeners.notifyTrainingFinished(); }  void addListener(TrainingListener listener); void setProgressMonitorFrequency(int value); void train();  }### Answer:
@Test public void when_training_expect_listenersToBeCalled() { syncLearning.train(); verify(mockTrainingListener, times(1)).onTrainingStart(); verify(mockTrainingListener, times(100)).onNewEpoch(eq(syncLearning)); verify(mockTrainingListener, times(100)).onEpochTrainingResult(eq(syncLearning), any(IDataManager.StatEntry.class)); verify(mockTrainingListener, times(1)).onTrainingEnd(); }
@Test public void when_trainingStartCanContinueFalse_expect_trainingStopped() { when(mockTrainingListener.onTrainingStart()).thenReturn(TrainingListener.ListenerResponse.STOP); syncLearning.train(); verify(mockTrainingListener, times(1)).onTrainingStart(); verify(mockTrainingListener, times(0)).onNewEpoch(eq(syncLearning)); verify(mockTrainingListener, times(0)).onEpochTrainingResult(eq(syncLearning), any(IDataManager.StatEntry.class)); verify(mockTrainingListener, times(1)).onTrainingEnd(); }
@Test public void when_newEpochCanContinueFalse_expect_trainingStopped() { when(mockTrainingListener.onNewEpoch(eq(syncLearning))) .thenReturn(TrainingListener.ListenerResponse.CONTINUE) .thenReturn(TrainingListener.ListenerResponse.CONTINUE) .thenReturn(TrainingListener.ListenerResponse.STOP); syncLearning.train(); verify(mockTrainingListener, times(1)).onTrainingStart(); verify(mockTrainingListener, times(3)).onNewEpoch(eq(syncLearning)); verify(mockTrainingListener, times(2)).onEpochTrainingResult(eq(syncLearning), any(IDataManager.StatEntry.class)); verify(mockTrainingListener, times(1)).onTrainingEnd(); }
@Test public void when_epochTrainingResultCanContinueFalse_expect_trainingStopped() { when(mockTrainingListener.onEpochTrainingResult(eq(syncLearning), any(IDataManager.StatEntry.class))) .thenReturn(TrainingListener.ListenerResponse.CONTINUE) .thenReturn(TrainingListener.ListenerResponse.CONTINUE) .thenReturn(TrainingListener.ListenerResponse.STOP); syncLearning.train(); verify(mockTrainingListener, times(1)).onTrainingStart(); verify(mockTrainingListener, times(3)).onNewEpoch(eq(syncLearning)); verify(mockTrainingListener, times(3)).onEpochTrainingResult(eq(syncLearning), any(IDataManager.StatEntry.class)); verify(mockTrainingListener, times(1)).onTrainingEnd(); }