diff --git a/steps/ApplyBeam.cc b/steps/ApplyBeam.cc
index e0ebeb07e72dc64f17aa83f9e96c53070dac55ce..defe69b4ccdad243c273c636da62d1b645275638 100644
--- a/steps/ApplyBeam.cc
+++ b/steps/ApplyBeam.cc
@@ -194,14 +194,19 @@ void ApplyBeam::showTimings(std::ostream& os, double duration) const {
   os << " ApplyBeam " << itsName << '\n';
 }
 
-bool ApplyBeam::processMultithreaded(const DPBuffer& bufin, size_t thread) {
+bool ApplyBeam::processMultithreaded(std::unique_ptr<base::DPBuffer> buffer,
+                                     size_t thread) {
   itsTimer.start();
-  itsBuffer.copy(bufin);
-  casacore::Complex* data = itsBuffer.GetData().data();
 
-  float* weight = itsBuffer.GetWeights().data();
+  // Ensure that data and weight are independent and not references as ApplyBeam
+  // updates both
+  buffer->MakeIndependent(kDataField | kWeightsField);
 
-  const double time = itsBuffer.getTime();
+  std::complex<float>* data = buffer->GetData().data();
+
+  float* weight = buffer->GetWeights().data();
+
+  const double time = buffer->getTime();
 
   // Set up directions for beam evaluation
   everybeam::vector3r_t srcdir;
@@ -242,7 +247,7 @@ bool ApplyBeam::processMultithreaded(const DPBuffer& bufin, size_t thread) {
             itsBeamValues[thread], itsInvert, itsMode, itsUpdateWeights);
 
   itsTimer.stop();
-  getNextStep()->process(itsBuffer);
+  getNextStep()->process(std::move(buffer));
   return false;
 }
 
diff --git a/steps/ApplyBeam.h b/steps/ApplyBeam.h
index f40254cec079603891bacd15cf11e4a4dc8d00d3..e0c49a07257e934645aa55a28c2eb862b7eb94bc 100644
--- a/steps/ApplyBeam.h
+++ b/steps/ApplyBeam.h
@@ -54,13 +54,14 @@ class ApplyBeam : public Step {
   /// Process the data.
   /// It keeps the data.
   /// When processed, it invokes the process function of the next step.
-  bool process(const base::DPBuffer& buffer) override {
-    return processMultithreaded(buffer, 0);
+  bool process(std::unique_ptr<base::DPBuffer> buffer) override {
+    return processMultithreaded(std::move(buffer), 0);
   }
 
   /// If apply beam is called from multiple threads, it needs the thread index
   /// to determine what scratch space to use etc.
-  bool processMultithreaded(const base::DPBuffer&, size_t thread);
+  bool processMultithreaded(std::unique_ptr<base::DPBuffer> buffer,
+                            size_t thread);
 
   /// Finish the processing of this step and subsequent steps.
   void finish() override;
@@ -125,7 +126,6 @@ class ApplyBeam : public Step {
                                  casacore::MDirection::Convert& measConverter);
 
   string itsName;
-  base::DPBuffer itsBuffer;
   bool itsInvert;
   bool itsUpdateWeights;
   std::vector<string> itsDirectionStr;
diff --git a/steps/test/unit/tApplyBeam.cc b/steps/test/unit/tApplyBeam.cc
index 369f0a886a91814a2b7cefecbcaffb39b19e5759..cb10134f702cd8a5da8a878a41a7c687ffaf03d0 100644
--- a/steps/test/unit/tApplyBeam.cc
+++ b/steps/test/unit/tApplyBeam.cc
@@ -4,7 +4,9 @@
 #include "../../ApplyBeam.h"
 
 #include <boost/test/unit_test.hpp>
+#include <xtensor/xcomplex.hpp>
 
+#include "mock/ThrowStep.h"
 #include "../../../common/ParameterSet.h"
 
 using dp3::steps::ApplyBeam;
@@ -12,6 +14,166 @@ using dp3::steps::Step;
 
 BOOST_AUTO_TEST_SUITE(apply_beam)
 
+namespace {
+const double kTime{4.87128e+09};
+const double kExposure{10.0139};
+}  // namespace
+
+// Create and populate a buffer with the bare minimum values required to run
+// ApplyBeam succesfully
+std::unique_ptr<dp3::base::DPBuffer> CreateBuffer(
+    xt::xtensor<std::complex<float>, 3>& data, xt::xtensor<float, 3>& weights) {
+  std::unique_ptr<dp3::base::DPBuffer> buffer =
+      std::make_unique<dp3::base::DPBuffer>(kTime, kExposure);
+
+  buffer->ResizeData(data.shape());
+  buffer->ResizeWeights(weights.shape());
+
+  buffer->GetData() = data;
+  buffer->GetWeights() = weights;
+
+  return buffer;
+}
+
+// Create and populate an info object with the bare minimum values required to
+// run ApplyBeam succesfully
+dp3::base::DPInfo MakeInfo() {
+  dp3::base::DPInfo info(4, 8, 0, "HBA_DUAL_INNER");
+  info.setMsName("tNDPPP-generic.MS");
+  info.setChannels({1.34288e+08, 1.34312e+08}, {24414.1, 24414.1},
+                   {24414.1, 24414.1}, {24414.1, 24414.1}, 1.34375e+08, 0);
+
+  info.setTimes(3.0, 3.0, 5.0);
+
+  std::vector<int> antenna_1{0};
+  std::vector<int> antenna_2{0};
+
+  std::vector<string> antenna_names{"CS001HBA0", "CS002HBA0"};
+
+  std::vector<casacore::MPosition> antenna_position(2);
+  casacore::Vector<double> vals(3);
+  vals[0] = 3828763;
+  vals[1] = 442449;
+  vals[2] = 5064923;
+  antenna_position[0] = casacore::MPosition(
+      casacore::Quantum<casacore::Vector<double>>(vals, "m"),
+      casacore::MPosition::ITRF);
+  vals[0] = 3828746;
+  vals[1] = 442592;
+  vals[2] = 5064924;
+  antenna_position[1] = casacore::MPosition(
+      casacore::Quantum<casacore::Vector<double>>(vals, "m"),
+      casacore::MPosition::ITRF);
+
+  std::vector<double> antenna_diameter(2.0, 70.0);
+  info.setAntennas(antenna_names, antenna_diameter, antenna_position, antenna_1,
+                   antenna_2);
+  return info;
+}
+
+// Test step for end of "pipeline"; Terminate and run tests against expected
+// data
+class TestOutput : public dp3::steps::test::ThrowStep {
+ public:
+  TestOutput(xt::xtensor<std::complex<float>, 3>& expected_data,
+             xt::xtensor<float, 3>& expected_weights)
+      : expected_data_(expected_data), expected_weights_(expected_weights) {}
+
+  bool process(std::unique_ptr<dp3::base::DPBuffer> buffer) override {
+    BOOST_CHECK(xt::allclose(buffer->GetData(), expected_data_));
+    BOOST_TEST(buffer->GetWeights() == expected_weights_,
+               boost::test_tools::per_element());
+
+    BOOST_CHECK(buffer->getTime() == kTime);
+    BOOST_CHECK(buffer->getExposure() == kExposure);
+    return true;
+  }
+  void finish() override {}
+
+ private:
+  xt::xtensor<std::complex<float>, 3> expected_data_;
+  xt::xtensor<float, 3> expected_weights_;
+};
+
+// Perform a very small/minimal run of the ArrayBeam step and compare against
+// expected result to help catch any regressions
+BOOST_AUTO_TEST_CASE(test_step_basic) {
+  xt::xtensor<std::complex<float>, 3> test_data = {
+      {{{0.000105909, -6.15896e-06},
+        {-5.75999e-05, -0.000169081},
+        {6.09389e-05, -0.000144006},
+        {7.58708e-05, -0.000118892}},
+       {{5.04177e-05, -0.000176506},
+        {0.000159816, 3.01513e-06},
+        {8.10528e-05, 9.37562e-05},
+        {0.000141897, -7.32e-05}}},
+      {{{0.000170118, 5.01791e-05},
+        {6.19825e-05, 3.1506e-05},
+        {0.000152869, -8.22876e-05},
+        {3.44475e-05, -0.000179837}},
+       {{0.000143976, -0.000107417},
+        {0.000130452, -3.40554e-05},
+        {0.000100048, 7.11484e-05},
+        {-0.000127001, -6.57001e-05}}},
+      {{{6.60433e-05, -9.32823e-05},
+        {6.31116e-05, 0.000100894},
+        {-9.42722e-05, -0.000188316},
+        {-5.7855e-05, -0.000132138}},
+       {{0.000108384, 8.16866e-05},
+        {-0.00012894, -0.000180018},
+        {0.000106929, -2.96774e-05},
+        {0.000101331, -1.57673e-05}}}};
+  xt::xtensor<float, 3> test_weights = {
+      {{7.429210e+08, 1.792340e+09, 5.485560e+08, 1.411610e+09},
+       {4.384190e+08, 5.486580e+08, 5.480330e+08, 4.262130e+08}},
+      {{1.745190e+09, 8.292680e+08, 1.791950e+09, 1.608370e+09},
+       {4.232110e+08, 4.369040e+08, 6.651330e+08, 1.709300e+09}},
+      {{9.355210e+08, 1.963980e+09, 6.532890e+08, 5.810230e+08},
+       {5.264440e+08, 1.566430e+09, 1.715470e+09, 1.069660e+09}}};
+  xt::xtensor<std::complex<float>, 3> expected_data = {
+      {{{886.133, -2354.56},
+        {771.412, -602.496},
+        {-367.09, -843.605},
+        {883.182, 710.44}},
+       {{2249.85, -563.42},
+        {199.536, 273.074},
+        {926.346, -564.403},
+        {-137.817, -1638.45}}},
+      {{{0.000170118, 5.01791e-05},
+        {6.19825e-05, 3.1506e-05},
+        {0.000152869, -8.22876e-05},
+        {3.44475e-05, -0.000179837}},
+       {{0.000143976, -0.000107417},
+        {0.000130452, -3.40554e-05},
+        {0.000100048, 7.11484e-05},
+        {-0.000127001, -6.57001e-05}}},
+      {{{6.60433e-05, -9.32823e-05},
+        {6.31116e-05, 0.000100894},
+        {-9.42722e-05, -0.000188316},
+        {-5.7855e-05, -0.000132138}},
+       {{0.000108384, 8.16866e-05},
+        {-0.00012894, -0.000180018},
+        {0.000106929, -2.96774e-05},
+        {0.000101331, -1.57673e-05}}}};
+  xt::xtensor<float, 3> expected_weights = {
+      {{7.42921e+08, 1.79234e+09, 5.48556e+08, 1.41161e+09},
+       {4.38419e+08, 5.48658e+08, 5.48033e+08, 4.26213e+08}},
+      {{1.74519e+09, 8.29268e+08, 1.79195e+09, 1.60837e+09},
+       {4.23211e+08, 4.36904e+08, 6.65133e+08, 1.7093e+09}},
+      {{9.35521e+08, 1.96398e+09, 6.53289e+08, 5.81023e+08},
+       {5.26444e+08, 1.56643e+09, 1.71547e+09, 1.06966e+09}}};
+
+  auto apply_beam =
+      std::make_unique<ApplyBeam>(dp3::common::ParameterSet(), "", false);
+  auto test_output_step =
+      std::make_shared<TestOutput>(expected_data, expected_weights);
+  apply_beam->setNextStep(test_output_step);
+  apply_beam->updateInfo(MakeInfo());
+
+  auto buffer = CreateBuffer(test_data, test_weights);
+  apply_beam->process(std::move(buffer));
+}
+
 BOOST_AUTO_TEST_CASE(fields_defaults) {
   dp3::common::ParameterSet parset;
   const ApplyBeam apply_beam(parset, "");