From c864c9022f8dfb22e2a07cdbc504c280a886a57a Mon Sep 17 00:00:00 2001
From: Gemma Guest <gemma.guest@stfc.ac.uk>
Date: Fri, 26 Jul 2019 09:28:44 +0100
Subject: [PATCH] Add main window presenter tests

Add an interface to the BatchPresenterFactory.

Re #26498
---
 qt/scientific_interfaces/CMakeLists.txt       |   1 +
 .../GUI/Batch/BatchPresenterFactory.h         |   6 +-
 .../GUI/Batch/CMakeLists.txt                  |   1 +
 .../GUI/Batch/IBatchPresenterFactory.h        |  24 ++
 .../GUI/MainWindow/MainWindowPresenter.cpp    |  13 +-
 .../GUI/MainWindow/MainWindowPresenter.h      |  19 +-
 .../GUI/MainWindow/QtMainWindowView.cpp       |   2 +-
 .../GUI/MainWindow/QtMainWindowView.h         |   1 +
 .../Batch/BatchPresenterTest.h                |   1 +
 .../MainWindow/MainWindowPresenterTest.h      | 319 ++++++++++++++++++
 .../MainWindow/MockMainWindowPresenter.h      |  27 ++
 .../MainWindow/MockMainWindowView.h           |  30 ++
 .../test/ISISReflectometry/ReflMockObjects.h  |  35 +-
 13 files changed, 436 insertions(+), 43 deletions(-)
 create mode 100644 qt/scientific_interfaces/ISISReflectometry/GUI/Batch/IBatchPresenterFactory.h
 create mode 100644 qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MainWindowPresenterTest.h
 create mode 100644 qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowPresenter.h
 create mode 100644 qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowView.h

diff --git a/qt/scientific_interfaces/CMakeLists.txt b/qt/scientific_interfaces/CMakeLists.txt
index a7e00c44dbf..0868a052d9e 100644
--- a/qt/scientific_interfaces/CMakeLists.txt
+++ b/qt/scientific_interfaces/CMakeLists.txt
@@ -65,6 +65,7 @@ set(TEST_FILES
     test/ISISReflectometry/Instrument/InstrumentOptionDefaultsTest.h
     test/ISISReflectometry/Runs/CatalogRunNotifierTest.h
     test/ISISReflectometry/Runs/RunsPresenterTest.h
+    test/ISISReflectometry/MainWindow/MainWindowPresenterTest.h
     test/ISISReflectometry/Runs/SearchResultTest.h
     test/ISISReflectometry/Save/SavePresenterTest.h
     test/ISISReflectometry/Common/PlotterTestQt4.h
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/BatchPresenterFactory.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/BatchPresenterFactory.h
index a65085140a6..f72b0cd91d2 100644
--- a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/BatchPresenterFactory.h
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/BatchPresenterFactory.h
@@ -14,13 +14,15 @@
 #include "GUI/Runs/RunsPresenterFactory.h"
 #include "GUI/Save/SavePresenterFactory.h"
 #include "IBatchPresenter.h"
+#include "IBatchPresenterFactory.h"
 #include "IBatchView.h"
 #include <memory>
 
 namespace MantidQt {
 namespace CustomInterfaces {
 namespace ISISReflectometry {
-class BatchPresenterFactory {
+
+class BatchPresenterFactory : public IBatchPresenterFactory {
 public:
   BatchPresenterFactory(
       // cppcheck-suppress passedByValue
@@ -35,7 +37,7 @@ public:
         m_instrumentPresenterFactory(std::move(instrumentPresenterFactory)),
         m_savePresenterFactory(std::move(savePresenterFactory)) {}
 
-  std::unique_ptr<IBatchPresenter> make(IBatchView *view) {
+  std::unique_ptr<IBatchPresenter> make(IBatchView *view) override {
     auto runsPresenter = m_runsPresenterFactory.make(view->runs());
     auto eventPresenter = m_eventPresenterFactory.make(view->eventHandling());
     auto experimentPresenter =
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/CMakeLists.txt b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/CMakeLists.txt
index a4d50738491..f4f52daacf7 100644
--- a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/CMakeLists.txt
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/CMakeLists.txt
@@ -15,6 +15,7 @@ set(BATCH_INC_FILES
     IBatchView.h
     IBatchJobAlgorithm.h
     IBatchJobRunner.h
+    IBatchPresenterFactory.h
     BatchPresenter.h
     BatchPresenterFactory.h
     QtBatchView.h
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/IBatchPresenterFactory.h b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/IBatchPresenterFactory.h
new file mode 100644
index 00000000000..52f448e4185
--- /dev/null
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/Batch/IBatchPresenterFactory.h
@@ -0,0 +1,24 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTID_ISISREFLECTOMETRY_IBATCHPRESENTERFACTORY_H
+#define MANTID_ISISREFLECTOMETRY_IBATCHPRESENTERFACTORY_H
+
+#include <memory>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class IBatchPresenter;
+class IBatchView;
+
+class IBatchPresenterFactory {
+public:
+  virtual ~IBatchPresenterFactory() = default;
+  virtual std::unique_ptr<IBatchPresenter> make(IBatchView *view) = 0;
+};
+} // namespace CustomInterfaces
+} // namespace MantidQt
+#endif // MANTID_ISISREFLECTOMETRY_IBATCHPRESENTERFACTORY_H
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.cpp
index d62d6bf4642..f1315a347f4 100644
--- a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.cpp
@@ -5,6 +5,7 @@
 //     & Institut Laue - Langevin
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "MainWindowPresenter.h"
+#include "GUI/Batch/IBatchPresenterFactory.h"
 #include "GUI/Common/IMessageHandler.h"
 #include "GUI/Runs/IRunsPresenter.h"
 #include "IMainWindowView.h"
@@ -24,7 +25,7 @@ namespace ISISReflectometry {
  */
 MainWindowPresenter::MainWindowPresenter(
     IMainWindowView *view, IMessageHandler *messageHandler,
-    BatchPresenterFactory batchPresenterFactory)
+    std::unique_ptr<IBatchPresenterFactory> batchPresenterFactory)
     : m_view(view), m_messageHandler(messageHandler),
       m_batchPresenterFactory(std::move(batchPresenterFactory)) {
   view->subscribe(this);
@@ -53,13 +54,13 @@ void MainWindowPresenter::notifyCloseBatchRequested(int batchIndex) {
 }
 
 void MainWindowPresenter::notifyAutoreductionResumed() {
-  for (auto batchPresenter : m_batchPresenters) {
+  for (auto &batchPresenter : m_batchPresenters) {
     batchPresenter->anyBatchAutoreductionResumed();
   }
 }
 
 void MainWindowPresenter::notifyAutoreductionPaused() {
-  for (auto batchPresenter : m_batchPresenters) {
+  for (auto &batchPresenter : m_batchPresenters) {
     batchPresenter->anyBatchAutoreductionResumed();
   }
 }
@@ -67,7 +68,7 @@ void MainWindowPresenter::notifyAutoreductionPaused() {
 void MainWindowPresenter::notifyHelpPressed() { showHelp(); }
 
 bool MainWindowPresenter::isAnyBatchProcessing() const {
-  for (auto batchPresenter : m_batchPresenters) {
+  for (auto &batchPresenter : m_batchPresenters) {
     if (batchPresenter->isProcessing())
       return true;
   }
@@ -75,7 +76,7 @@ bool MainWindowPresenter::isAnyBatchProcessing() const {
 }
 
 bool MainWindowPresenter::isAnyBatchAutoreducing() const {
-  for (auto batchPresenter : m_batchPresenters) {
+  for (auto &batchPresenter : m_batchPresenters) {
     if (batchPresenter->isAutoreducing())
       return true;
   }
@@ -83,7 +84,7 @@ bool MainWindowPresenter::isAnyBatchAutoreducing() const {
 }
 
 void MainWindowPresenter::addNewBatch(IBatchView *batchView) {
-  m_batchPresenters.emplace_back(m_batchPresenterFactory.make(batchView));
+  m_batchPresenters.emplace_back(m_batchPresenterFactory->make(batchView));
   m_batchPresenters.back()->acceptMainPresenter(this);
 
   // starts in the paused state
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.h b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.h
index 29caa2e4a68..9a34b8b90b0 100644
--- a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.h
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/MainWindowPresenter.h
@@ -8,7 +8,7 @@
 #define MANTID_ISISREFLECTOMETRY_MAINWINDOWPRESENTER_H
 
 #include "Common/DllConfig.h"
-#include "GUI/Batch/BatchPresenterFactory.h"
+#include "GUI/Batch/IBatchPresenter.h"
 #include "IMainWindowPresenter.h"
 #include "IMainWindowView.h"
 #include <memory>
@@ -17,6 +17,7 @@ namespace MantidQt {
 namespace CustomInterfaces {
 namespace ISISReflectometry {
 
+class IBatchPresenterFactory;
 class IMainWindowView;
 class IMessageHandler;
 
@@ -30,8 +31,9 @@ class MANTIDQT_ISISREFLECTOMETRY_DLL MainWindowPresenter
       public IMainWindowPresenter {
 public:
   /// Constructor
-  MainWindowPresenter(IMainWindowView *view, IMessageHandler *messageHandler,
-                      BatchPresenterFactory batchPresenterFactory);
+  MainWindowPresenter(
+      IMainWindowView *view, IMessageHandler *messageHandler,
+      std::unique_ptr<IBatchPresenterFactory> batchPresenterFactory);
 
   // IMainWindowPresenter overrides
   bool isAnyBatchProcessing() const override;
@@ -44,14 +46,15 @@ public:
   void notifyNewBatchRequested() override;
   void notifyCloseBatchRequested(int batchIndex) override;
 
+protected:
+  IMainWindowView *m_view;
+  IMessageHandler *m_messageHandler;
+  std::vector<std::unique_ptr<IBatchPresenter>> m_batchPresenters;
+  std::unique_ptr<IBatchPresenterFactory> m_batchPresenterFactory;
+
 private:
   void showHelp();
   void addNewBatch(IBatchView *batchView);
-
-  IMainWindowView *m_view;
-  IMessageHandler *m_messageHandler;
-  BatchPresenterFactory m_batchPresenterFactory;
-  std::vector<std::shared_ptr<IBatchPresenter>> m_batchPresenters;
 };
 } // namespace ISISReflectometry
 } // namespace CustomInterfaces
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.cpp b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.cpp
index c22b9531d67..b22e4da909a 100644
--- a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.cpp
@@ -92,7 +92,7 @@ void QtMainWindowView::initLayout() {
   auto makeExperimentPresenter = ExperimentPresenterFactory(thetaTolerance);
   auto makeInstrumentPresenter = InstrumentPresenterFactory();
 
-  auto makeBatchPresenter = BatchPresenterFactory(
+  auto makeBatchPresenter = std::make_unique<BatchPresenterFactory>(
       std::move(makeRunsPresenter), std::move(makeEventPresenter),
       std::move(makeExperimentPresenter), std::move(makeInstrumentPresenter),
       std::move(makeSaveSettingsPresenter));
diff --git a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.h b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.h
index 0154005818f..df3e9e7604c 100644
--- a/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.h
+++ b/qt/scientific_interfaces/ISISReflectometry/GUI/MainWindow/QtMainWindowView.h
@@ -7,6 +7,7 @@
 #ifndef MANTID_ISISREFLECTOMETRY_QTMAINWINDOWVIEW_H
 #define MANTID_ISISREFLECTOMETRY_QTMAINWINDOWVIEW_H
 
+#include "GUI/Batch/IBatchPresenterFactory.h"
 #include "GUI/Common/IMessageHandler.h"
 #include "GUI/Common/IPythonRunner.h"
 #include "IMainWindowPresenter.h"
diff --git a/qt/scientific_interfaces/test/ISISReflectometry/Batch/BatchPresenterTest.h b/qt/scientific_interfaces/test/ISISReflectometry/Batch/BatchPresenterTest.h
index b659dfc8359..9e3767a302b 100644
--- a/qt/scientific_interfaces/test/ISISReflectometry/Batch/BatchPresenterTest.h
+++ b/qt/scientific_interfaces/test/ISISReflectometry/Batch/BatchPresenterTest.h
@@ -9,6 +9,7 @@
 
 #include "../../../ISISReflectometry/GUI/Batch/BatchPresenter.h"
 #include "../../../ISISReflectometry/TestHelpers/ModelCreationHelper.h"
+#include "../MainWindow/MockMainWindowPresenter.h"
 #include "../ReflMockObjects.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MockBatchView.h"
diff --git a/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MainWindowPresenterTest.h b/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MainWindowPresenterTest.h
new file mode 100644
index 00000000000..5758f589bc7
--- /dev/null
+++ b/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MainWindowPresenterTest.h
@@ -0,0 +1,319 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTID_CUSTOMINTERFACES_MAINWINDOWPRESENTERTEST_H_
+#define MANTID_CUSTOMINTERFACES_MAINWINDOWPRESENTERTEST_H_
+
+#include "../../../ISISReflectometry/Common/ModelCreationHelper.h"
+#include "../../../ISISReflectometry/GUI/MainWindow/MainWindowPresenter.h"
+#include "../Batch/MockBatchView.h"
+#include "../ReflMockObjects.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MockMainWindowView.h"
+
+#include <cxxtest/TestSuite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace MantidQt::CustomInterfaces;
+using namespace MantidQt::CustomInterfaces::ModelCreationHelper;
+using MantidQt::API::IConfiguredAlgorithm_sptr;
+using testing::AtLeast;
+using testing::Mock;
+using testing::NiceMock;
+using testing::Return;
+using testing::ReturnRef;
+using testing::_;
+
+class MainWindowPresenterTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static MainWindowPresenterTest *createSuite() {
+    return new MainWindowPresenterTest();
+  }
+  static void destroySuite(MainWindowPresenterTest *suite) { delete suite; }
+
+  MainWindowPresenterTest() : m_view(), m_messageHandler() {
+    Mantid::API::FrameworkManager::Instance();
+    // Get the view to return a couple of batches by default
+    m_batchViews.emplace_back(new MockBatchView);
+    m_batchViews.emplace_back(new MockBatchView);
+    ON_CALL(m_view, batches()).WillByDefault(Return(m_batchViews));
+  }
+
+  void testPresenterSubscribesToView() {
+    EXPECT_CALL(m_view, subscribe(_)).Times(1);
+    auto presenter = makePresenter();
+    verifyAndClear();
+  }
+
+  void testConstructorAddsBatchPresenterForAllBatchViews() {
+    EXPECT_CALL(m_view, batches()).Times(1);
+    for (auto batchPresenter : m_batchPresenters)
+      expectBatchAdded(batchPresenter);
+
+    auto presenter = makePresenter();
+    TS_ASSERT_EQUALS(presenter.m_batchPresenters.size(), m_batchViews.size());
+    verifyAndClear();
+  }
+
+  void testBatchPresenterAddedWhenNewBatchRequested() {
+    auto presenter = makePresenter();
+    auto batchView = new NiceMock<MockBatchView>();
+    EXPECT_CALL(m_view, newBatch())
+        .Times(1)
+        .WillOnce(Return(dynamic_cast<IBatchView *>(batchView)));
+    auto batchPresenter = new NiceMock<MockBatchPresenter>();
+    EXPECT_CALL(*m_makeBatchPresenter, makeProxy(batchView))
+        .Times(1)
+        .WillOnce(Return(batchPresenter));
+    expectBatchAdded(batchPresenter);
+
+    presenter.notifyNewBatchRequested();
+    verifyAndClear();
+  }
+
+  void testBatchRemovedWhenCloseBatchRequested() {
+    auto presenter = makePresenter();
+    auto const batchIndex = 0;
+    expectBatchCanBeClosed(batchIndex);
+    expectBatchRemovedFromView(batchIndex);
+    presenter.notifyCloseBatchRequested(batchIndex);
+    assertFirstBatchWasRemovedFromModel(presenter);
+    verifyAndClear();
+  }
+
+  void testBatchNotRemovedIfRequestCloseFailed() {
+    auto presenter = makePresenter();
+    auto const batchIndex = 0;
+    expectRequestCloseBatchFailed(batchIndex);
+    expectBatchNotRemovedFromView(batchIndex);
+    presenter.notifyCloseBatchRequested(batchIndex);
+    assertBatchNotRemovedFromModel(presenter);
+    verifyAndClear();
+  }
+
+  void testBatchNotRemovedIfAutoreducing() {
+    auto presenter = makePresenter();
+    auto const batchIndex = 0;
+    expectBatchIsAutoreducing(batchIndex);
+    expectBatchNotRemovedFromView(batchIndex);
+    presenter.notifyCloseBatchRequested(batchIndex);
+    assertBatchNotRemovedFromModel(presenter);
+    verifyAndClear();
+  }
+
+  void testBatchNotRemovedIfProcessing() {
+    auto presenter = makePresenter();
+    auto const batchIndex = 0;
+    expectBatchIsProcessing(batchIndex);
+    expectBatchNotRemovedFromView(batchIndex);
+    presenter.notifyCloseBatchRequested(batchIndex);
+    assertBatchNotRemovedFromModel(presenter);
+    verifyAndClear();
+  }
+
+  void testWarningGivenIfRemoveBatchWhileAutoreducing() {
+    auto presenter = makePresenter();
+    auto const batchIndex = 0;
+    expectBatchIsAutoreducing(batchIndex);
+    expectCannotCloseBatchWarning();
+    presenter.notifyCloseBatchRequested(batchIndex);
+    verifyAndClear();
+  }
+
+  void testWarningGivenIfRemoveBatchWhileProcessing() {
+    auto presenter = makePresenter();
+    auto const batchIndex = 0;
+    expectBatchIsProcessing(batchIndex);
+    expectCannotCloseBatchWarning();
+    presenter.notifyCloseBatchRequested(batchIndex);
+    verifyAndClear();
+  }
+
+  void testAutoreductionResumedNotifiesAllBatchPresenters() {
+    auto presenter = makePresenter();
+    for (auto batchPresenter : m_batchPresenters)
+      EXPECT_CALL(*batchPresenter, anyBatchAutoreductionResumed());
+    presenter.notifyAutoreductionResumed();
+    verifyAndClear();
+  }
+
+  void testAutoreductionPausedNotifiesAllBatchPresenters() {
+    auto presenter = makePresenter();
+    for (auto batchPresenter : m_batchPresenters)
+      EXPECT_CALL(*batchPresenter, anyBatchAutoreductionPaused());
+    presenter.notifyAutoreductionPaused();
+    verifyAndClear();
+  }
+
+  void testAnyBatchIsProcessing() {
+    auto presenter = makePresenter();
+    expectBatchIsNotProcessing(0);
+    expectBatchIsProcessing(1);
+    auto isProcessing = presenter.isAnyBatchProcessing();
+    TS_ASSERT_EQUALS(isProcessing, true);
+    verifyAndClear();
+  }
+
+  void testNoBatchesAreProcessing() {
+    auto presenter = makePresenter();
+    expectBatchIsNotProcessing(0);
+    expectBatchIsNotProcessing(1);
+    auto isProcessing = presenter.isAnyBatchProcessing();
+    TS_ASSERT_EQUALS(isProcessing, false);
+    verifyAndClear();
+  }
+
+  void testAnyBatchIsAutoreducing() {
+    auto presenter = makePresenter();
+    expectBatchIsNotAutoreducing(0);
+    expectBatchIsAutoreducing(1);
+    auto isAutoreducing = presenter.isAnyBatchAutoreducing();
+    TS_ASSERT_EQUALS(isAutoreducing, true);
+    verifyAndClear();
+  }
+
+  void testNoBatchesAreAutoreducing() {
+    auto presenter = makePresenter();
+    expectBatchIsNotAutoreducing(0);
+    expectBatchIsNotAutoreducing(1);
+    auto isAutoreducing = presenter.isAnyBatchAutoreducing();
+    TS_ASSERT_EQUALS(isAutoreducing, false);
+    verifyAndClear();
+  }
+
+private:
+  NiceMock<MockMainWindowView> m_view;
+  NiceMock<MockMessageHandler> m_messageHandler;
+  std::vector<IBatchView *> m_batchViews;
+  std::vector<NiceMock<MockBatchPresenter> *> m_batchPresenters;
+  NiceMock<MockBatchPresenterFactory> *m_makeBatchPresenter;
+
+  class MainWindowPresenterFriend : public MainWindowPresenter {
+    friend class MainWindowPresenterTest;
+
+  public:
+    MainWindowPresenterFriend(
+        IMainWindowView *view, IMessageHandler *messageHandler,
+        std::unique_ptr<IBatchPresenterFactory> makeBatchPresenter)
+        : MainWindowPresenter(view, messageHandler,
+                              std::move(makeBatchPresenter)) {}
+  };
+
+  MainWindowPresenterFriend makePresenter() {
+    // Make the batch presenter factory
+    auto makeBatchPresenter =
+        std::make_unique<NiceMock<MockBatchPresenterFactory>>();
+    m_makeBatchPresenter = makeBatchPresenter.get();
+    // Set up a mock batch presenter for each view to be returned from the
+    // factory
+    for (auto batchView : m_batchViews) {
+      auto batchPresenter = new NiceMock<MockBatchPresenter>();
+      m_batchPresenters.push_back(batchPresenter);
+      ON_CALL(*m_makeBatchPresenter, makeProxy(batchView))
+          .WillByDefault(Return(batchPresenter));
+    }
+    // Make the presenter
+    auto presenter = MainWindowPresenterFriend(&m_view, &m_messageHandler,
+                                               std::move(makeBatchPresenter));
+    return presenter;
+  }
+
+  void verifyAndClear() {
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_messageHandler));
+    for (auto batchPresenter : m_batchPresenters)
+      TS_ASSERT(Mock::VerifyAndClearExpectations(batchPresenter));
+    m_batchPresenters.clear();
+  }
+
+  void expectBatchAdded(MockBatchPresenter *batchPresenter) {
+    EXPECT_CALL(*batchPresenter, acceptMainPresenter(_)).Times(1);
+    EXPECT_CALL(*batchPresenter, reductionPaused()).Times(1);
+    EXPECT_CALL(*batchPresenter, anyBatchAutoreductionPaused()).Times(1);
+  }
+
+  void expectBatchCanBeClosed(int batchIndex) {
+    EXPECT_CALL(*m_batchPresenters[batchIndex], isAutoreducing())
+        .Times(1)
+        .WillOnce(Return(false));
+    EXPECT_CALL(*m_batchPresenters[batchIndex], isProcessing())
+        .Times(1)
+        .WillOnce(Return(false));
+    EXPECT_CALL(*m_batchPresenters[batchIndex], requestClose())
+        .Times(1)
+        .WillOnce(Return(true));
+  }
+
+  void expectBatchIsAutoreducing(int batchIndex) {
+    EXPECT_CALL(*m_batchPresenters[batchIndex], isAutoreducing())
+        .Times(1)
+        .WillOnce(Return(true));
+  }
+
+  void expectBatchIsProcessing(int batchIndex) {
+    EXPECT_CALL(*m_batchPresenters[batchIndex], isProcessing())
+        .Times(1)
+        .WillOnce(Return(true));
+  }
+
+  void expectBatchIsNotAutoreducing(int batchIndex) {
+    EXPECT_CALL(*m_batchPresenters[batchIndex], isAutoreducing())
+        .Times(1)
+        .WillOnce(Return(false));
+  }
+
+  void expectBatchIsNotProcessing(int batchIndex) {
+    EXPECT_CALL(*m_batchPresenters[batchIndex], isProcessing())
+        .Times(1)
+        .WillOnce(Return(false));
+  }
+
+  void expectRequestCloseBatchFailed(int batchIndex) {
+    EXPECT_CALL(*m_batchPresenters[batchIndex], requestClose())
+        .Times(1)
+        .WillOnce(Return(false));
+  }
+
+  void expectBatchRemovedFromView(int batchIndex) {
+    EXPECT_CALL(m_view, removeBatch(batchIndex)).Times(1);
+  }
+
+  void expectBatchNotRemovedFromView(int batchIndex) {
+    EXPECT_CALL(m_view, removeBatch(batchIndex)).Times(0);
+  }
+
+  void expectCannotCloseBatchWarning() {
+    EXPECT_CALL(m_messageHandler,
+                giveUserCritical("Cannot close batch while processing or "
+                                 "autoprocessing is in progress",
+                                 "Error"))
+        .Times(1);
+  }
+
+  void assertFirstBatchWasRemovedFromModel(
+      MainWindowPresenterFriend const &presenter) {
+    TS_ASSERT_EQUALS(presenter.m_batchPresenters.size(), 1);
+    // Note that our local list of raw pointers is not updated so
+    // the first item is invalid and the second item is now the
+    // only remaining batch presenter in the model
+    TS_ASSERT_EQUALS(presenter.m_batchPresenters[0].get(),
+                     m_batchPresenters[1]);
+  }
+
+  void
+  assertBatchNotRemovedFromModel(MainWindowPresenterFriend const &presenter) {
+    TS_ASSERT_EQUALS(presenter.m_batchPresenters.size(),
+                     m_batchPresenters.size());
+    for (size_t index = 0; index < m_batchPresenters.size(); ++index)
+      TS_ASSERT_EQUALS(presenter.m_batchPresenters[index].get(),
+                       m_batchPresenters[index]);
+  }
+};
+
+#endif // MANTID_CUSTOMINTERFACES_MAINWINDOWPRESENTERTEST_H_
diff --git a/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowPresenter.h b/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowPresenter.h
new file mode 100644
index 00000000000..98cb2989eb1
--- /dev/null
+++ b/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowPresenter.h
@@ -0,0 +1,27 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "../../../ISISReflectometry/GUI/MainWindow/IMainWindowPresenter.h"
+#include "MantidKernel/WarningSuppressions.h"
+#include <gmock/gmock.h>
+
+GNU_DIAG_OFF_SUGGEST_OVERRIDE
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class MockMainWindowPresenter : public IMainWindowPresenter {
+public:
+  MOCK_METHOD1(settingsChanged, void(int));
+  MOCK_CONST_METHOD0(isAnyBatchProcessing, bool());
+  MOCK_CONST_METHOD0(isAnyBatchAutoreducing, bool());
+  MOCK_METHOD0(notifyAutoreductionResumed, void());
+  MOCK_METHOD0(notifyAutoreductionPaused, void());
+
+  ~MockMainWindowPresenter() override{};
+};
+} // namespace CustomInterfaces
+} // namespace MantidQt
+GNU_DIAG_ON_SUGGEST_OVERRIDE
diff --git a/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowView.h b/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowView.h
new file mode 100644
index 00000000000..2888d864bdb
--- /dev/null
+++ b/qt/scientific_interfaces/test/ISISReflectometry/MainWindow/MockMainWindowView.h
@@ -0,0 +1,30 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "../../../ISISReflectometry/GUI/MainWindow/IMainWindowView.h"
+#include "MantidKernel/WarningSuppressions.h"
+#include <gmock/gmock.h>
+
+GNU_DIAG_OFF_SUGGEST_OVERRIDE
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class MockMainWindowView : public IMainWindowView {
+public:
+  MOCK_METHOD2(askUserYesNo, bool(const std::string &, const std::string &));
+  MOCK_METHOD2(giveUserWarning, void(const std::string &, const std::string &));
+  MOCK_METHOD2(giveUserCritical,
+               void(const std::string &, const std::string &));
+  MOCK_METHOD2(giveUserInfo, void(const std::string &, const std::string &));
+  MOCK_METHOD0(newBatch, IBatchView *());
+  MOCK_METHOD1(subscribe, void(MainWindowSubscriber *));
+  MOCK_METHOD1(removeBatch, void(int));
+  MOCK_CONST_METHOD0(batches, std::vector<IBatchView *>());
+  ~MockMainWindowView() override{};
+};
+} // namespace CustomInterfaces
+} // namespace MantidQt
+GNU_DIAG_ON_SUGGEST_OVERRIDE
diff --git a/qt/scientific_interfaces/test/ISISReflectometry/ReflMockObjects.h b/qt/scientific_interfaces/test/ISISReflectometry/ReflMockObjects.h
index 0882f984325..520b5f20d15 100644
--- a/qt/scientific_interfaces/test/ISISReflectometry/ReflMockObjects.h
+++ b/qt/scientific_interfaces/test/ISISReflectometry/ReflMockObjects.h
@@ -10,6 +10,7 @@
 #include "GUI/Batch/IBatchJobAlgorithm.h"
 #include "GUI/Batch/IBatchJobRunner.h"
 #include "GUI/Batch/IBatchPresenter.h"
+#include "GUI/Batch/IBatchPresenterFactory.h"
 #include "GUI/Common/IMessageHandler.h"
 #include "GUI/Common/IPythonRunner.h"
 #include "GUI/Event/IEventPresenter.h"
@@ -40,35 +41,20 @@ using namespace Mantid::API;
 
 GNU_DIAG_OFF_SUGGEST_OVERRIDE
 
-/**** Views ****/
-class MockMainWindowView : public IMainWindowView {
+/**** Factories ****/
+class MockBatchPresenterFactory : public IBatchPresenterFactory {
 public:
-  MOCK_METHOD2(askUserYesNo, bool(const std::string &, const std::string &));
-  MOCK_METHOD2(giveUserWarning, void(const std::string &, const std::string &));
-  MOCK_METHOD2(giveUserCritical,
-               void(const std::string &, const std::string &));
-  MOCK_METHOD2(giveUserInfo, void(const std::string &, const std::string &));
-  MOCK_METHOD0(newBatch, IBatchView *());
-  MOCK_METHOD1(subscribe, void(MainWindowSubscriber *));
-  MOCK_METHOD1(removeBatch, void(int));
-  MOCK_CONST_METHOD0(batches, std::vector<IBatchView *>());
-  ~MockMainWindowView() override{};
+  MOCK_METHOD1(makeProxy, IBatchPresenter *(IBatchView *));
+  std::unique_ptr<IBatchPresenter> make(IBatchView *view) {
+    return std::unique_ptr<IBatchPresenter>(makeProxy(view));
+  }
 };
-/**** Presenters ****/
 
-class MockMainWindowPresenter : public IMainWindowPresenter {
-public:
-  MOCK_METHOD1(settingsChanged, void(int));
-  MOCK_CONST_METHOD0(isAnyBatchProcessing, bool());
-  MOCK_CONST_METHOD0(isAnyBatchAutoreducing, bool());
-  MOCK_METHOD0(notifyAutoreductionResumed, void());
-  MOCK_METHOD0(notifyAutoreductionPaused, void());
-
-  ~MockMainWindowPresenter() override{};
-};
+/**** Presenters ****/
 
 class MockBatchPresenter : public IBatchPresenter {
 public:
+  MOCK_METHOD1(acceptMainPresenter, void(IMainWindowPresenter *));
   MOCK_METHOD0(notifyReductionResumed, void());
   MOCK_METHOD0(notifyReductionPaused, void());
   MOCK_METHOD0(notifyAutoreductionResumed, void());
@@ -89,9 +75,6 @@ public:
   MOCK_CONST_METHOD0(requestClose, bool());
   MOCK_CONST_METHOD0(instrument, Mantid::Geometry::Instrument_const_sptr());
   MOCK_CONST_METHOD0(instrumentName, std::string());
-
-  // Calls we don't care about
-  void acceptMainPresenter(IMainWindowPresenter *) override{};
 };
 
 class MockRunsPresenter : public IRunsPresenter {
-- 
GitLab