diff --git a/test/unit/engine_target.js b/test/unit/engine_target.js
index 1e7d5a8b5..986038774 100644
--- a/test/unit/engine_target.js
+++ b/test/unit/engine_target.js
@@ -148,6 +148,182 @@ test('deleteVariable2', t => {
     t.end();
 });
 
+test('duplicateVariable creates a new variable with a new ID by default', t => {
+    const target = new Target();
+    target.createVariable('a var ID', 'foo', Variable.SCALAR_TYPE);
+    t.equal(Object.keys(target.variables).length, 1);
+    const originalVariable = target.variables['a var ID'];
+    originalVariable.value = 10;
+    const newVariable = target.duplicateVariable('a var ID');
+    // Duplicating a variable should not add the variable to the current target
+    t.equal(Object.keys(target.variables).length, 1);
+    // Duplicate variable should have a different ID from the original unless specified to keep the original ID.
+    t.notEqual(newVariable.id, 'a var ID');
+    t.type(target.variables[newVariable.id], 'undefined');
+
+    // Duplicate variable should start out with the same value as the original variable
+    t.equal(newVariable.value, originalVariable.value);
+
+    // Modifying one variable should not modify the other
+    newVariable.value = 15;
+    t.notEqual(newVariable.value, originalVariable.value);
+    t.equal(originalVariable.value, 10);
+
+    t.end();
+});
+
+test('duplicateVariable creates a new variable with a original ID if specified', t => {
+    const target = new Target();
+    target.createVariable('a var ID', 'foo', Variable.SCALAR_TYPE);
+    t.equal(Object.keys(target.variables).length, 1);
+    const originalVariable = target.variables['a var ID'];
+    originalVariable.value = 10;
+    const newVariable = target.duplicateVariable('a var ID', true);
+    // Duplicating a variable should not add the variable to the current target
+    t.equal(Object.keys(target.variables).length, 1);
+    // Duplicate variable should have the same ID as the original when specified
+    t.equal(newVariable.id, 'a var ID');
+
+    // Duplicate variable should start out with the same value as the original variable
+    t.equal(newVariable.value, originalVariable.value);
+
+    // Modifying one variable should not modify the other
+    newVariable.value = 15;
+    t.notEqual(newVariable.value, originalVariable.value);
+    t.equal(originalVariable.value, 10);
+    // The target should still have the original variable with the original value
+    t.equal(target.variables['a var ID'].value, 10);
+
+    t.end();
+});
+
+test('duplicateVariable returns null if variable with specified ID does not exist', t => {
+    const target = new Target();
+
+    const variable = target.duplicateVariable('a var ID');
+    t.equal(variable, null);
+    t.equal(Object.keys(target.variables).length, 0);
+
+    target.createVariable('var id', 'foo', Variable.SCALAR_TYPE);
+    t.equal(Object.keys(target.variables).length, 1);
+
+    const anotherVariable = target.duplicateVariable('another var ID');
+    t.equal(anotherVariable, null);
+    t.equal(Object.keys(target.variables).length, 1);
+    t.type(target.variables['another var ID'], 'undefined');
+    t.type(target.variables['var id'], 'object');
+    t.notEqual(target.variables['var id'], null);
+
+    t.end();
+});
+
+test('duplicateVariables duplicates all variables', t => {
+    const target = new Target();
+    target.createVariable('var ID 1', 'var1', Variable.SCALAR_TYPE);
+    target.createVariable('var ID 2', 'var2', Variable.SCALAR_TYPE);
+
+    t.equal(Object.keys(target.variables).length, 2);
+
+    const var1 = target.variables['var ID 1'];
+    const var2 = target.variables['var ID 2'];
+
+    var1.value = 3;
+    var2.value = 'foo';
+
+    const duplicateVariables = target.duplicateVariables();
+
+    // Duplicating a target's variables should not change the target's own variables.
+    t.equal(Object.keys(target.variables).length, 2);
+    t.equal(Object.keys(duplicateVariables).length, 2);
+
+    // Should be able to find original var IDs in both this target's variables and
+    // the duplicate variables since a blocks container was not specified.
+    t.equal(target.variables.hasOwnProperty('var ID 1'), true);
+    t.equal(target.variables.hasOwnProperty('var ID 2'), true);
+    t.equal(duplicateVariables.hasOwnProperty('var ID 1'), true);
+    t.equal(duplicateVariables.hasOwnProperty('var ID 1'), true);
+
+    // Values of the duplicate varaiables should match the value of the original values at the time of duplication
+    t.equal(target.variables['var ID 1'].value, duplicateVariables['var ID 1'].value);
+    t.equal(duplicateVariables['var ID 1'].value, 3);
+    t.equal(target.variables['var ID 2'].value, duplicateVariables['var ID 2'].value);
+    t.equal(duplicateVariables['var ID 2'].value, 'foo');
+
+    // The two sets of variables should still be distinct, modifying the target's variables
+    // should not affect the duplicated variables, and vice-versa
+
+    var1.value = 10;
+    t.equal(target.variables['var ID 1'].value, 10);
+    t.equal(duplicateVariables['var ID 1'].value, 3); // should remain unchanged from initial value
+
+    duplicateVariables['var ID 2'].value = 'bar';
+    t.equal(target.variables['var ID 2'].value, 'foo');
+
+    // Deleting a variable on the target should not change the duplicated variables
+    target.deleteVariable('var ID 1');
+    t.equal(Object.keys(target.variables).length, 1);
+    t.equal(Object.keys(duplicateVariables).length, 2);
+    t.type(duplicateVariables['var ID 1'], 'object');
+    t.notEqual(duplicateVariables['var ID 1'], null);
+
+    t.end();
+});
+
+test('duplicateVariables re-IDs variables when a block container is provided', t => {
+    const target = new Target();
+
+    target.createVariable('mock var id', 'a mock variable', Variable.SCALAR_TYPE);
+    target.createVariable('another var id', 'var2', Variable.SCALAR_TYPE);
+
+    // Create a block on the target which references the variable with id 'mock var id'
+    target.blocks.createBlock(adapter(events.mockVariableBlock)[0]);
+
+    t.type(target.blocks.getBlock('a block'), 'object');
+    t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object');
+    t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id');
+    t.equal(target.blocks.getBlock('a block').fields.VARIABLE.value, 'a mock variable');
+
+    // Deep clone this target's blocks to pass in to 'duplicateVariables'
+    const copiedBlocks = target.blocks.duplicate();
+
+    // The copied block should still have the same ID, and its VARIABLE field should still refer to
+    // the original variable id
+    t.type(copiedBlocks.getBlock('a block'), 'object');
+    t.type(copiedBlocks.getBlock('a block').fields.VARIABLE, 'object');
+    t.equal(copiedBlocks.getBlock('a block').fields.VARIABLE.id, 'mock var id');
+    t.equal(copiedBlocks.getBlock('a block').fields.VARIABLE.value, 'a mock variable');
+
+    const duplicateVariables = target.duplicateVariables(copiedBlocks);
+
+    // Duplicate variables should have new IDs
+    t.equal(Object.keys(duplicateVariables).length, 2);
+    t.type(duplicateVariables['mock var id'], 'undefined');
+    t.type(duplicateVariables['another var id'], 'undefined');
+
+    // Duplicate variables still have the same names..
+    const dupes = Object.values(duplicateVariables);
+    const dupeVarNames = dupes.map(v => v.name);
+
+    t.notEqual(dupeVarNames.indexOf('a mock variable'), -1);
+    t.notEqual(dupeVarNames.indexOf('var2'), -1);
+
+    // Duplicating variables should not change blocks on current target
+    t.type(target.blocks.getBlock('a block'), 'object');
+    t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id');
+    t.equal(target.blocks.getBlock('a block').fields.VARIABLE.value, 'a mock variable');
+
+    // The copied blocks passed into duplicateVariables should now reference the new
+    // variable ID
+    const mockVariableDupe = dupes[dupeVarNames.indexOf('a mock variable')];
+    const mockVarDupeID = mockVariableDupe.id;
+
+    t.type(copiedBlocks.getBlock('a block'), 'object');
+    t.equal(copiedBlocks.getBlock('a block').fields.VARIABLE.id, mockVarDupeID);
+    t.equal(copiedBlocks.getBlock('a block').fields.VARIABLE.value, 'a mock variable');
+
+    t.end();
+});
+
 test('lookupOrCreateList creates a list if var with given id or var with given name does not exist', t => {
     const target = new Target();
     const variables = target.variables;