diff --git a/test/edu/nps/moves/dis7/EntityStatePduTest.java b/test/edu/nps/moves/dis7/EntityStatePduTest.java
index 065f305d6c1e4e0cdd4377f783420b8f20b17f99..0bc08196eea9fd72b9fe736ef45aad287dd3258f 100644
--- a/test/edu/nps/moves/dis7/EntityStatePduTest.java
+++ b/test/edu/nps/moves/dis7/EntityStatePduTest.java
@@ -4,56 +4,19 @@
  */
 package edu.nps.moves.dis7;
 
-import edu.nps.moves.dis7.*;
 import edu.nps.moves.dis7.entities.usa.munition.other.M1A2;
 import edu.nps.moves.dis7.enumerations.Country;
 import edu.nps.moves.dis7.enumerations.EntityKind;
-import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
 import edu.nps.moves.dis7.utilities.PduFactory;
 import edu.nps.moves.dis7.enumerations.PlatformDomain;
 import org.junit.jupiter.api.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 @DisplayName("Entity State Pdu Test")
-public class EntityStatePduTest
+public class EntityStatePduTest extends PduTest
 {
-  DisThreadedNetworkInterface             disNetworkInterface;
-  Pdu                                     receivedPdu;
-  DisThreadedNetworkInterface.PduListener pduListener;
-    
-  @BeforeAll
-  public static void setUpClass()
-  {
-    System.out.println("EntityStatePduTest");
-  }
-
-  @AfterAll
-  public static void tearDownClass()
-  {
-  }
-
-  @BeforeEach
-  public void setUp()
-  {
-      disNetworkInterface = new DisThreadedNetworkInterface();
-      pduListener = new DisThreadedNetworkInterface.PduListener() {
-          @Override
-          public void incomingPdu(Pdu newPdu) {
-              setUpReceiver(newPdu);
-  }
-      };
-      disNetworkInterface.addListener(pduListener);
-  }
-
-  @AfterEach
-  public void tearDown()
-  {
-      disNetworkInterface.removeListener(pduListener);
-      disNetworkInterface.kill();
-      disNetworkInterface = null;
-  }
-
   @Test
+  @Override
   public void testRoundTrip()
   {
     PduFactory pduFactory = new PduFactory();
@@ -75,11 +38,12 @@ public class EntityStatePduTest
     // or simply use an enumeration by name, with accompanying import statement above
     espdu.setEntityType(new M1A2()); 
         
-    testOne(espdu);
-    testOne(espdu.setEntityID(entityID).setEntityType(entityType));   
+    testOnePdu(espdu);
+    testOnePdu(espdu.setEntityID(entityID).setEntityType(entityType));   
   }
   
-  private void testOne(Pdu newPdu)
+  @Override
+  protected void testOnePdu(Pdu newPdu)
   {
      sendPdu(newPdu); // will wait a while
      assertTrue(receivedPdu != null,         "No response from network receive");
@@ -134,34 +98,12 @@ public class EntityStatePduTest
      receivedPdu = null; // ensure cleared prior to next test
   }
   
-  private void sendPdu(Pdu pdu)
-  {
-    try {
-      disNetworkInterface.send(pdu);
-      Thread.sleep(100);
-    }
-    catch (InterruptedException ex) {
-      System.err.println("Error sending Multicast: " + ex.getLocalizedMessage());
-      System.exit(1);
+    public static void main(String[] args)
+    {
+        EntityStatePduTest entityStatePduTest = new EntityStatePduTest();
+        
+        entityStatePduTest.setUp();
+        entityStatePduTest.testRoundTrip();
+        entityStatePduTest.tearDown();
     }
-  }
- 
-  private boolean compare(Pdu pdu1, Pdu pdu2)
-  {
-    return pdu1.equalsImpl(pdu2);
-  }
-  
-  private void setUpReceiver(Pdu newPdu)
-  {
-    receivedPdu = newPdu;
-  }
-  
-  public static void main(String[] args)
-  {
-    EntityStatePduTest entityStatePduTest = new EntityStatePduTest();
-    
-    entityStatePduTest.setUp();
-    entityStatePduTest.testRoundTrip();
-    entityStatePduTest.tearDown();
-  }
 }
diff --git a/test/edu/nps/moves/dis7/PduTest.java b/test/edu/nps/moves/dis7/PduTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..899c83b56a541e3d06123a062846eac45416e0ab
--- /dev/null
+++ b/test/edu/nps/moves/dis7/PduTest.java
@@ -0,0 +1,115 @@
+/* Copyright (c) 1995-2020 held by the author(s).  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other materials provided with the
+      distribution.
+    * Neither the names of the Naval Postgraduate School (NPS)
+      Modeling Virtual Environments and Simulation (MOVES) Institute
+      (https://www.nps.edu and https://my.nps.edu/web/moves)
+      nor the names of its contributors may be used to endorse or
+      promote products derived from this software without specific
+      prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package edu.nps.moves.dis7;
+
+import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ *
+ * @author brutzman
+ */
+
+abstract public class PduTest
+{
+
+    @BeforeAll
+    public static void setUpClass()
+    {
+        System.out.println("EntityStatePduTest");
+    }
+
+    @AfterAll
+    public static void tearDownClass()
+    {
+    }
+
+    DisThreadedNetworkInterface disNetworkInterface;
+    Pdu receivedPdu;
+    DisThreadedNetworkInterface.PduListener pduListener;
+
+    @BeforeEach
+    public void setUp()
+    {
+        disNetworkInterface = new DisThreadedNetworkInterface();
+        pduListener = new DisThreadedNetworkInterface.PduListener()
+        {
+            @Override
+            public void incomingPdu(Pdu newPdu)
+            {
+                setUpReceiver(newPdu);
+            }
+        };
+        disNetworkInterface.addListener(pduListener);
+    }
+
+    @AfterEach
+    public void tearDown()
+    {
+        disNetworkInterface.removeListener(pduListener);
+        disNetworkInterface.kill();
+        disNetworkInterface = null;
+    }
+
+    protected void sendPdu(Pdu pdu)
+    {
+        try
+        {
+            disNetworkInterface.send(pdu);
+            Thread.sleep(100);
+        } catch (InterruptedException ex)
+        {
+            System.err.println("Error sending Multicast: " + ex.getLocalizedMessage());
+            System.exit(1);
+        }
+    }
+
+    protected boolean compare(Pdu pdu1, Pdu pdu2)
+    {
+        return pdu1.equalsImpl(pdu2);
+    }
+
+    protected void setUpReceiver(Pdu newPdu)
+    {
+        receivedPdu = newPdu;
+    }
+
+    public abstract void testRoundTrip();
+
+    protected abstract void testOnePdu(Pdu newPdu);
+    
+}