Index: src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py	(revision ff3b293197970c44a7188c9d3c2fd7fa7a83536e)
+++ src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py	(revision 00b7ddf001d6174678202ae0a8cb46f506e0c637)
@@ -181,4 +181,20 @@
     item_list[0].setCheckable(True)
     model.appendRow(item_list)
+
+def addHeadingRowToModel(model, name):
+    """adds a non-interactive top-level row to the model"""
+    header_row = [QtGui.QStandardItem() for i in range(5)]
+    header_row[0].setText(name)
+
+    font = header_row[0].font()
+    font.setBold(True)
+    header_row[0].setFont(font)
+
+    for item in header_row:
+        item.setEditable(False)
+        item.setCheckable(False)
+        item.setSelectable(False)
+
+    model.appendRow(header_row)
 
 def addHeadersToModel(model):
Index: src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision ef3494b390e91b547bf3e44241dd5e4fb4c0afeb)
+++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 00b7ddf001d6174678202ae0a8cb46f506e0c637)
@@ -669,5 +669,7 @@
         Return list of all parameters for the current model
         """
-        return [self._model_model.item(row).text() for row in range(self._model_model.rowCount())]
+        return [self._model_model.item(row).text()
+                for row in range(self._model_model.rowCount())
+                if self.isCheckable(row)]
 
     def modifyViewOnRow(self, row, font=None, brush=None):
@@ -697,4 +699,5 @@
         assert isinstance(constraint, Constraint)
         assert 0 <= row <= self._model_model.rowCount()
+        assert self.isCheckable(row)
 
         item = QtGui.QStandardItem()
@@ -717,4 +720,5 @@
         max_col = self.lstParams.itemDelegate().param_max
         for row in self.selectedParameters():
+            assert(self.isCheckable(row))
             param = self._model_model.item(row, 0).text()
             value = self._model_model.item(row, 1).text()
@@ -759,4 +763,6 @@
         max_col = self.lstParams.itemDelegate().param_max
         for row in range(self._model_model.rowCount()):
+            if not self.isCheckable(row):
+                continue
             if not self.rowHasConstraint(row):
                 continue
@@ -787,10 +793,12 @@
         For the given row, return its constraint, if any
         """
-        try:
+        if self.isCheckable(row):
             item = self._model_model.item(row, 1)
-            return item.child(0).data()
-        except AttributeError:
-            # return none when no constraints
-            return None
+            try:
+                return item.child(0).data()
+            except AttributeError:
+                # return none when no constraints
+                pass
+        return None
 
     def rowHasConstraint(self, row):
@@ -798,9 +806,10 @@
         Finds out if row of the main model has a constraint child
         """
-        item = self._model_model.item(row, 1)
-        if item.hasChildren():
-            c = item.child(0).data()
-            if isinstance(c, Constraint):
-                return True
+        if self.isCheckable(row):
+            item = self._model_model.item(row, 1)
+            if item.hasChildren():
+                c = item.child(0).data()
+                if isinstance(c, Constraint):
+                    return True
         return False
 
@@ -809,9 +818,10 @@
         Finds out if row of the main model has an active constraint child
         """
-        item = self._model_model.item(row, 1)
-        if item.hasChildren():
-            c = item.child(0).data()
-            if isinstance(c, Constraint) and c.active:
-                return True
+        if self.isCheckable(row):
+            item = self._model_model.item(row, 1)
+            if item.hasChildren():
+                c = item.child(0).data()
+                if isinstance(c, Constraint) and c.active:
+                    return True
         return False
 
@@ -820,9 +830,10 @@
         Finds out if row of the main model has an active, nontrivial constraint child
         """
-        item = self._model_model.item(row, 1)
-        if item.hasChildren():
-            c = item.child(0).data()
-            if isinstance(c, Constraint) and c.func and c.active:
-                return True
+        if self.isCheckable(row):
+            item = self._model_model.item(row, 1)
+            if item.hasChildren():
+                c = item.child(0).data()
+                if isinstance(c, Constraint) and c.func and c.active:
+                    return True
         return False
 
@@ -1556,5 +1567,5 @@
             # internal so can use closure for param_dict
             param_name = str(self._model_model.item(row, 0).text())
-            if param_name not in list(param_dict.keys()):
+            if not self.isCheckable(row) or param_name not in list(param_dict.keys()):
                 return
             # modify the param value
@@ -1568,5 +1579,5 @@
             # Utility function for updateof polydispersity part of the main model
             param_name = str(self._model_model.item(row, 0).text())+'.width'
-            if param_name not in list(param_dict.keys()):
+            if not self.isCheckable(row) or param_name not in list(param_dict.keys()):
                 return
             # modify the param value
@@ -1711,5 +1722,6 @@
         """
         for row_i in range(self._magnet_model.rowCount()):
-            func(row_i)
+            if self.isCheckable(row_i):
+                func(row_i)
 
     def updateMagnetModelFromList(self, param_dict):
@@ -2031,20 +2043,11 @@
         self.shell_names = self.shellNamesList()
 
-        # Add a header
-        header_row = [QtGui.QStandardItem() for i in range(5)]
-        header_row[0].setText(self.kernel_module.name)
-        font = header_row[0].font()
-        font.setBold(True)
-        header_row[0].setFont(font)
-        for item in header_row:
-            item.setEditable(False)
-            item.setCheckable(False)
-            item.setSelectable(False)
-
-        self._model_model.appendRow(header_row)
-
-        # Update the QModel
+        # Get new rows for QModel
         new_rows = FittingUtilities.addParametersToModel(self.model_parameters, self.kernel_module, self.is2D)
 
+        # Add heading row
+        FittingUtilities.addHeadingRowToModel(self._model_model, model_name)
+
+        # Update QModel
         for row in new_rows:
             self._model_model.appendRow(row)
@@ -2064,18 +2067,11 @@
         self.kernel_module = MultiplicationModel(form_kernel, structure_kernel)
 
-        # Add a header
-        header_row = [QtGui.QStandardItem() for i in range(5)]
-        header_row[0].setText(structure_kernel._model_info.name)
-        font = header_row[0].font()
-        font.setBold(True)
-        header_row[0].setFont(font)
-        for item in header_row:
-            item.setEditable(False)
-            item.setCheckable(False)
-            item.setSelectable(False)
-
-        self._model_model.appendRow(header_row)
-
+        # Get new rows for QModel
         new_rows = FittingUtilities.addSimpleParametersToModel(structure_parameters, self.is2D)
+
+        # Add heading row
+        FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor)
+
+        # Update QModel
         for row in new_rows:
             self._model_model.appendRow(row)
@@ -2517,4 +2513,6 @@
         def updateFunctionCaption(row):
             # Utility function for update of polydispersity function name in the main model
+            if not self.isCheckable(row):
+                return
             param_name = str(self._model_model.item(row, 0).text())
             if param_name !=  param.name:
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 6dbff184fba73897683dff97bef2e92fd7609f0b)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 00b7ddf001d6174678202ae0a8cb46f506e0c637)
@@ -255,5 +255,5 @@
 
         # We have 4 more rows now
-        self.assertEqual(self.widget._model_model.rowCount(), rowcount+4)
+        self.assertEqual(self.widget._model_model.rowCount(), rowcount+5)
 
         # Switch models
@@ -275,5 +275,5 @@
         self.widget.cbStructureFactor.setCurrentIndex(last_index-1)
         # Do we have all the rows?
-        self.assertEqual(self.widget._model_model.rowCount(), 4)
+        self.assertEqual(self.widget._model_model.rowCount(), 5)
 
         # Are the command buttons properly enabled?
@@ -496,5 +496,9 @@
         Test opening of the load file dialog for 'array' polydisp. function
         """
+
+        # open a non-existent file
         filename = os.path.join("UnitTesting", "testdata_noexist.txt")
+        with self.assertRaises(OSError, msg="testdata_noexist.txt should be a non-existent file"):
+            os.stat(filename)
         QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,''))
         self.widget.show()
@@ -512,5 +516,12 @@
 
         # good file
+        # TODO: this depends on the working directory being src/sas/qtgui,
+        # TODO: which isn't convenient if you want to run this test suite
+        # TODO: individually
         filename = os.path.join("UnitTesting", "testdata.txt")
+        try:
+            os.stat(filename)
+        except OSError:
+            self.assertTrue(False, "testdata.txt does not exist")
         QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,''))
 
@@ -1012,5 +1023,5 @@
 
          # Check the model
-        self.assertEqual(self.widget._model_model.rowCount(), 6)
+        self.assertEqual(self.widget._model_model.rowCount(), 7)
         self.assertEqual(self.widget._model_model.columnCount(), 5)
 
@@ -1128,5 +1139,5 @@
         # two rows selected
         index1 = self.widget.lstParams.model().index(1, 0, QtCore.QModelIndex())
-        index2 = self.widget.lstParams.model().index(2, 0, QtCore.QModelIndex())
+        index2 = self.widget.lstParams.model().index(3, 0, QtCore.QModelIndex())
         selection_model = self.widget.lstParams.selectionModel()
         selection_model.select(index1, selection_model.Select | selection_model.Rows)
@@ -1164,5 +1175,5 @@
         # several random parameters
         self.assertEqual(self.widget.getRowFromName('scale'), 0)
-        self.assertEqual(self.widget.getRowFromName('length'), 5)
+        self.assertEqual(self.widget.getRowFromName('length'), 6)
 
     def testGetParamNames(self):
@@ -1201,5 +1212,5 @@
         # Create a constraint object
         const = Constraint(parent=None, value=7.0)
-        row = 2
+        row = 3
 
         spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal)
@@ -1220,5 +1231,5 @@
         # assign complex constraint now
         const = Constraint(parent=None, param='radius', func='5*sld')
-        row = 4
+        row = 5
         # call the method tested
         self.widget.addConstraintToRow(constraint=const, row=row)
@@ -1279,7 +1290,14 @@
         self.widget.cbModel.setCurrentIndex(model_index)
 
+        row1 = 1
+        row2 = 5
+
+        param1 = "background"
+        param2 = "radius"
+
+        #default_value1 = "0.001"
+        default_value2 = "20"
+
         # select two rows
-        row1 = 1
-        row2 = 4
         index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex())
         index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex())
@@ -1298,10 +1316,10 @@
 
         # delete one of the constraints
-        self.widget.deleteConstraintOnParameter(param='background')
+        self.widget.deleteConstraintOnParameter(param=param1)
 
         # see that the other constraint is still present
-        cons = self.widget.getConstraintForRow(4) # 4 = radius
-        self.assertEqual(cons.param, "radius")
-        self.assertEqual(cons.value, "20")
+        cons = self.widget.getConstraintForRow(row2)
+        self.assertEqual(cons.param, param2)
+        self.assertEqual(cons.value, default_value2)
 
         # kill the other constraint
@@ -1309,5 +1327,5 @@
 
         # see that the other constraint is still present
-        self.assertEqual(self.widget.getConstraintsForModel(), [('radius', None)])
+        self.assertEqual(self.widget.getConstraintsForModel(), [(param2, None)])
 
     def testGetConstraintForRow(self):
@@ -1329,7 +1347,8 @@
         self.widget.cbModel.setCurrentIndex(model_index)
 
+        row1 = 1
+        row2 = 5
+
         # select two rows
-        row1 = 1
-        row2 = 4
         index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex())
         index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex())
@@ -1341,5 +1360,5 @@
         self.widget.addSimpleConstraint()
 
-        con_list = [False, True, False, False, True, False]
+        con_list = [False, True, False, False, False, True, False]
         new_list = []
         for row in range(self.widget._model_model.rowCount()):
@@ -1359,7 +1378,8 @@
         self.widget.cbModel.setCurrentIndex(model_index)
 
+        row1 = 1
+        row2 = 5
+
         # select two rows
-        row1 = 1
-        row2 = 4
         index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex())
         index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex())
@@ -1375,5 +1395,5 @@
         constraint_objects[0].active = False
 
-        con_list = [False, False, False, False, True, False]
+        con_list = [False, False, False, False, False, True, False]
         new_list = []
         for row in range(self.widget._model_model.rowCount()):
@@ -1396,7 +1416,14 @@
         self.assertEqual(self.widget.getConstraintsForModel(),[])
 
+        row1 = 1
+        row2 = 5
+
+        param1 = "background"
+        param2 = "radius"
+
+        default_value1 = "0.001"
+        default_value2 = "20"
+
         # select two rows
-        row1 = 1
-        row2 = 4
         index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex())
         index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex())
@@ -1410,28 +1437,31 @@
         # simple constraints
         # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')])
-        cons = self.widget.getConstraintForRow(1) # 1 - background
-        self.assertEqual(cons.param, "background")
-        self.assertEqual(cons.value, "0.001")
-        cons = self.widget.getConstraintForRow(4) # 4 = radius
-        self.assertEqual(cons.param, "radius")
-        self.assertEqual(cons.value, "20")
+        cons = self.widget.getConstraintForRow(row1)
+        self.assertEqual(cons.param, param1)
+        self.assertEqual(cons.value, default_value1)
+        cons = self.widget.getConstraintForRow(row2)
+        self.assertEqual(cons.param, param2)
+        self.assertEqual(cons.value, default_value2)
 
         objects = self.widget.getConstraintObjectsForModel()
         self.assertEqual(len(objects), 2)
-        self.assertEqual(objects[1].value, '20')
-        self.assertEqual(objects[0].param, 'background')
+        self.assertEqual(objects[1].value, default_value2)
+        self.assertEqual(objects[0].param, param1)
+
+        row = 0
+        param = "scale"
+        func = "5*sld"
 
         # add complex constraint
-        const = Constraint(parent=None, param='scale', func='5*sld')
-        row = 0
+        const = Constraint(parent=None, param=param, func=func)
         self.widget.addConstraintToRow(constraint=const, row=row)
         #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)])
-        cons = self.widget.getConstraintForRow(4) # 4 = radius
-        self.assertEqual(cons.param, "radius")
-        self.assertEqual(cons.value, "20")
+        cons = self.widget.getConstraintForRow(row2)
+        self.assertEqual(cons.param, param2)
+        self.assertEqual(cons.value, default_value2)
 
         objects = self.widget.getConstraintObjectsForModel()
         self.assertEqual(len(objects), 3)
-        self.assertEqual(objects[0].func, '5*sld')
+        self.assertEqual(objects[0].func, func)
 
     def testReplaceConstraintName(self):
