diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81fc6e90e2e0d76878556984b416a1ae5ad42260..2ef0ed0da3bc9f99b3249350d067edc712ba5d06 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ release.
 - Added backplane options for SunIllumination and SurfaceObliqueDetectorResolution to phocube [#5467](https://github.com/DOI-USGS/ISIS3/issues/5467)
 
 ### Changed
+- Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5571](https://github.com/USGS-Astrogeology/ISIS3/issues/5571)
 - Modified kaguyasp2isis to work with new (detached) data [#5436](https://github.com/DOI-USGS/ISIS3/issues/5436)
 - Added jigsaw error message for csminit'd images without csm parameters[#5486](https://github.com/DOI-USGS/ISIS3/issues/5486)
 - Changed `qwt` dependency version to 6.2.0 or below [#5498](https://github.com/DOI-USGS/ISIS3/issues/5498)
diff --git a/isis/src/base/apps/bandtrim/bandtrim.cpp b/isis/src/base/apps/bandtrim/bandtrim.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..07e60d98e349b4b23607e2fee3ba06126f8e9cc0
--- /dev/null
+++ b/isis/src/base/apps/bandtrim/bandtrim.cpp
@@ -0,0 +1,74 @@
+/** This is free and unencumbered software released into the public domain.
+
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
+
+/* SPDX-License-Identifier: CC0-1.0 */
+
+#include "bandtrim.h"
+
+#include "Cube.h"
+#include "ProcessByBrick.h"
+#include "SpecialPixel.h"
+
+namespace Isis {
+
+  // Process to trim spectral pixels if any are null
+  void BandTrimSpectral(Buffer &in, Buffer &out);
+
+  /**
+   * Bandtrim searches for NULL pixels in all bands of a cube.
+   * When a NULL pixel is found the corresponding pixel is set
+   * to NULL in all other bands.
+   *
+   * @param ui User Interface with application parameters
+   */
+  void bandtrim(UserInterface &ui) {
+  
+    // open cube
+    Cube icube;
+    icube.open(ui.GetCubeName("FROM"));
+
+    bandtrim(&icube, ui);
+  }
+
+
+  /**
+   * Bandtrim searches for NULL pixels in all bands of a cube.
+   * When a NULL pixel is found the corresponding pixel is set
+   * to NULL in all other bands.
+   *
+   * @param icube Input cube
+   * @param ui User Interface with application parameters
+   */
+  void bandtrim(Cube *icube, UserInterface &ui) {
+    ProcessByBrick p;
+    p.SetInputCube(icube);
+    p.SetBrickSize(1, 1, icube->bandCount());
+
+    QString fname = ui.GetCubeName("TO");
+    CubeAttributeOutput &atts = ui.GetOutputAttribute("TO");
+    p.SetOutputCube(fname, atts);
+
+    p.StartProcess(BandTrimSpectral);
+    p.EndProcess();
+  }
+
+  // Process to trim spectral pixels if any are null
+  void BandTrimSpectral(Buffer &in, Buffer &out) {
+    // Copy input to output and check to see if we should null
+    bool nullPixels = false;
+    for(int i = 0; i < in.size(); i++) {
+      out[i] = in[i];
+      if(in[i] == Isis::Null) nullPixels = true;
+    }
+
+    // Null all pixels in the spectra if necessary
+    if(nullPixels) {
+      for(int i = 0; i < in.size(); i++) {
+        out[i] = Isis::Null;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/isis/src/base/apps/bandtrim/bandtrim.h b/isis/src/base/apps/bandtrim/bandtrim.h
new file mode 100644
index 0000000000000000000000000000000000000000..03447a91d8235dc0ac1532ea772fe5928a1227d0
--- /dev/null
+++ b/isis/src/base/apps/bandtrim/bandtrim.h
@@ -0,0 +1,19 @@
+/** This is free and unencumbered software released into the public domain.
+
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
+
+/* SPDX-License-Identifier: CC0-1.0 */
+
+#ifndef bandtrim_h
+#define bandtrim_h
+
+#include "UserInterface.h"
+
+namespace Isis{  
+  extern void bandtrim(UserInterface &ui);
+  extern void bandtrim(Cube *iCube, UserInterface &ui);
+}
+
+#endif
diff --git a/isis/src/base/apps/bandtrim/bandtrim.xml b/isis/src/base/apps/bandtrim/bandtrim.xml
index 525a4e6f1988f956e032449fd4fa31c946b9d224..fd550ac3136b302ce8ab34049f7ae1deebf4f442 100644
--- a/isis/src/base/apps/bandtrim/bandtrim.xml
+++ b/isis/src/base/apps/bandtrim/bandtrim.xml
@@ -35,6 +35,9 @@
     <change name="Steven Lambright" date="2008-05-12">
       Removed references to CubeInfo 
     </change>
+    <change name="Ken Edmundson" date="2024-07-31">
+      Converted to callable app and converted Makefile tests to gtests. 
+    </change>
   </history>
 
   <groups>
diff --git a/isis/src/base/apps/bandtrim/main.cpp b/isis/src/base/apps/bandtrim/main.cpp
index d577d27cfe6151bb571f339472693aa5c3cb2af1..b163580e1cb535163df5f7f74014a942646ae273 100644
--- a/isis/src/base/apps/bandtrim/main.cpp
+++ b/isis/src/base/apps/bandtrim/main.cpp
@@ -1,34 +1,20 @@
-#include "Isis.h"
-#include "ProcessByBrick.h"
-#include "SpecialPixel.h"
+/** This is free and unencumbered software released into the public domain.
 
-using namespace std;
-using namespace Isis;
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
 
-void BandTrim(Buffer &in, Buffer &out);
+/* SPDX-License-Identifier: CC0-1.0 */
 
-void IsisMain() {
-  ProcessByBrick p;
-  Cube *icube = p.SetInputCube("FROM");
-  p.SetBrickSize(1, 1, icube->bandCount());
-  p.SetOutputCube("TO");
-  p.StartProcess(BandTrim);
-  p.EndProcess();
-}
+#include "Isis.h"
 
-// Trim spectral pixels if anyone of them is null
-void BandTrim(Buffer &in, Buffer &out) {
-  // Copy input to output and check to see if we should null
-  bool nullPixels = false;
-  for(int i = 0; i < in.size(); i++) {
-    out[i] = in[i];
-    if(in[i] == Isis::Null) nullPixels = true;
-  }
+#include "bandtrim.h"
 
-  // Null all pixels in the spectra if necessary
-  if(nullPixels) {
-    for(int i = 0; i < in.size(); i++) {
-      out[i] = Isis::Null;
-    }
-  }
+#include "Application.h"
+
+using namespace Isis;
+
+void IsisMain() {
+  UserInterface &ui = Application::GetUserInterface();
+  bandtrim(ui);
 }
diff --git a/isis/src/base/apps/bandtrim/tsts/Makefile b/isis/src/base/apps/bandtrim/tsts/Makefile
deleted file mode 100644
index 46d84c74c297304e943452a44e06b111f179a92b..0000000000000000000000000000000000000000
--- a/isis/src/base/apps/bandtrim/tsts/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BLANKS = "%-6s"    
-LENGTH = "%-40s"
-
-include $(ISISROOT)/make/isismake.tststree
diff --git a/isis/src/base/apps/bandtrim/tsts/default/Makefile b/isis/src/base/apps/bandtrim/tsts/default/Makefile
deleted file mode 100644
index 4360b7671b42fb0e561ca75731a7979fe4d3a95e..0000000000000000000000000000000000000000
--- a/isis/src/base/apps/bandtrim/tsts/default/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-APPNAME = bandtrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
-	$(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub > /dev/null;
diff --git a/isis/src/base/apps/bandtrim/tsts/oneband/Makefile b/isis/src/base/apps/bandtrim/tsts/oneband/Makefile
deleted file mode 100644
index 4360b7671b42fb0e561ca75731a7979fe4d3a95e..0000000000000000000000000000000000000000
--- a/isis/src/base/apps/bandtrim/tsts/oneband/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-APPNAME = bandtrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
-	$(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub > /dev/null;
diff --git a/isis/tests/FunctionalTestsBandtrim.cpp b/isis/tests/FunctionalTestsBandtrim.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..71f39029e5d8a45a4e5fb01c5271fb6664b11675
--- /dev/null
+++ b/isis/tests/FunctionalTestsBandtrim.cpp
@@ -0,0 +1,192 @@
+
+#include <QString>
+#include <QVector>
+
+#include "Brick.h"
+#include "CameraFixtures.h"
+#include "Histogram.h"
+#include "bandtrim.h"
+
+#include "gtest/gtest.h"
+
+using namespace Isis;
+
+static QString APP_XML = FileName("$ISISROOT/bin/xml/bandtrim.xml").expanded();
+
+/**
+   * BandtrimDefault Test
+   * 
+   * BandtrimDefault test given a single 5x5 input cube with 7 bands.
+   * One pixel in each band is set to Isis::Null as below.
+   * N implies a Null pixel, N1 is band 1, N2 is band 2, etc.
+   * All Null pixels should be duplicated across each band in the
+   * output Cube.
+   * 
+   * The output cube is verified by checking the histogram statistics
+   * for each band.
+   * 
+   * |  |N1|  |N2|  | 
+   * |  |  |  |  |  |
+   * |N3|  |N4|  |N5|
+   * |  |  |  |  |  |
+   * |  |N6|  |N7|  |
+   * 
+   * INPUT: testCube from DefaultCube fixture modified as above.
+   * 
+   * OUTPUT: bandtrimDefaultOut.cub
+   * 
+   */
+TEST_F(DefaultCube, FunctionalTestBandtrimDefault) {
+
+  // reduce test cube size, create seven bands
+  resizeCube(5, 5, 7);
+
+  // set one pixel in each of the seven bands to Isis::Null
+  // following the pattern in the comment block above
+
+  Brick b(1, 1, 1, testCube->pixelType()); // create buffer of size 1 pixel
+
+  b.SetBasePosition(2, 1, 1);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(4, 1, 2);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(1, 3, 3);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(3, 3, 4);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(5, 3, 5);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(2, 5, 6);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(4, 5, 7);
+  b[0] = Isis::Null;
+  testCube->write(b);
+  
+  // run bandtrim
+  QVector<QString> args = {"to=" + tempDir.path() + "/bandtrimDefaultOut.cub"};
+  UserInterface ui(APP_XML, args);
+
+  try {
+     bandtrim(testCube, ui);
+  }
+  catch(IException &e) {
+    FAIL() << e.toString().toStdString().c_str() << std::endl;
+  }
+
+  // Open output cube
+  Cube outCube(tempDir.path() + "/bandtrimDefaultOut.cub");
+
+  // validate histogram statistics for each band in output cube
+  std::unique_ptr<Histogram> band1Hist (outCube.histogram(1));
+  std::unique_ptr<Histogram> band2Hist (outCube.histogram(2));
+  std::unique_ptr<Histogram> band3Hist (outCube.histogram(3));
+  std::unique_ptr<Histogram> band4Hist (outCube.histogram(4));
+  std::unique_ptr<Histogram> band5Hist (outCube.histogram(5));
+  std::unique_ptr<Histogram> band6Hist (outCube.histogram(6));
+  std::unique_ptr<Histogram> band7Hist (outCube.histogram(7));
+
+  EXPECT_EQ(band1Hist->ValidPixels(), 18);
+  EXPECT_EQ(band1Hist->Average(), 13);
+  EXPECT_EQ(band1Hist->Sum(), 234);
+  EXPECT_EQ(band2Hist->ValidPixels(), 18);
+  EXPECT_EQ(band2Hist->Average(), 38);
+  EXPECT_EQ(band2Hist->Sum(), 684);
+  EXPECT_EQ(band3Hist->ValidPixels(), 18);
+  EXPECT_EQ(band3Hist->Average(), 63);
+  EXPECT_EQ(band3Hist->Sum(), 1134);
+  EXPECT_EQ(band4Hist->ValidPixels(), 18);
+  EXPECT_EQ(band4Hist->Average(), 88);
+  EXPECT_EQ(band4Hist->Sum(), 1584);
+  EXPECT_EQ(band5Hist->ValidPixels(), 18);
+  EXPECT_EQ(band5Hist->Average(), 113);
+  EXPECT_EQ(band5Hist->Sum(), 2034);
+  EXPECT_EQ(band6Hist->ValidPixels(), 18);
+  EXPECT_EQ(band6Hist->Average(), 138);
+  EXPECT_EQ(band6Hist->Sum(), 2484);
+  EXPECT_EQ(band7Hist->ValidPixels(), 18);
+  EXPECT_EQ(band7Hist->Average(), 163);
+  EXPECT_EQ(band7Hist->Sum(), 2934);
+
+  outCube.close();
+}
+
+
+/**
+   * BandtrimOneBand Test
+   * 
+   * BandtrimOneBand test given a single 5x5 input cube with 1 band.
+   * The four pixels in the upper left corner are set to Isis::Null
+   * as below. N implies a Null pixel.
+   * 
+   * The output cube is verified by checking histogram statistics.
+   * 
+   * |N|N| | | | 
+   * |N|N| | | |
+   * | | | | | |
+   * | | | | | |
+   * | | | | | |
+   * 
+   * INPUT: testCube from DefaultCube fixture
+   * 
+   * OUTPUT: bandtrimOneBandOut.cub
+   */
+TEST_F(DefaultCube, FunctionalTestBandtrimOneBand) {
+  
+  // reduce test cube size
+  resizeCube(5, 5, 1);
+
+  // set 4 pixel block in upper left corner to Isis::Null
+  Brick b(1, 1, 1, testCube->pixelType()); // create buffer of size 1 pixels
+  b.SetBasePosition(1, 1, 1);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(2, 1, 1);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(1, 2, 1);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  b.SetBasePosition(2, 2, 1);
+  b[0] = Isis::Null;
+  testCube->write(b);
+
+  // run bandtrim
+  QVector<QString> args = {"to=" + tempDir.path() + "/bandtrimOneBandOut.cub"};
+
+  UserInterface ui(APP_XML, args);
+
+  try {
+    bandtrim(testCube, ui);
+  }
+  catch(IException &e) {
+    FAIL() << e.toString().toStdString().c_str() << std::endl;
+  }
+
+  // Open output cube
+  Cube outCube(tempDir.path() + "/bandtrimOneBandOut.cub");
+
+  // validate histogram statistics for each band in output cube
+  std::unique_ptr<Histogram> band1Hist (outCube.histogram(1));
+
+  EXPECT_EQ(band1Hist->ValidPixels(), 21);
+  EXPECT_EQ(band1Hist->Average(), 14.714285714285714);
+  EXPECT_EQ(band1Hist->Sum(), 309);
+
+  outCube.close();
+}
+