diff --git a/modelling/src/model.cc b/modelling/src/model.cc
index 4504b7ea1c18b08e6dbcd982f3a53a8e65b29921..5740b93207b3c9d07a9dc790c1fe63f457609ad3 100644
--- a/modelling/src/model.cc
+++ b/modelling/src/model.cc
@@ -516,6 +516,8 @@ void MergeMHandle(const ModellingHandle& source_mhandle,
     if(c.IsValid() && n.IsValid()) ed.Connect(c, n);
   }
   ed.ReorderResidues(target_chain);
+  //fix torsions
+  ost::conop::AssignBackboneTorsions(target_chain);
 
   //delete the gaps in the target mhandle or shorten them...
   num.SetNum(start_resnum);
diff --git a/modelling/tests/test_modelling.py b/modelling/tests/test_modelling.py
index 56b5588d280c2c4cb944ba25be601cfdae5a89f5..7e1bebee4221149467c1cb435103ab598968bdc2 100644
--- a/modelling/tests/test_modelling.py
+++ b/modelling/tests/test_modelling.py
@@ -3,9 +3,10 @@ Unit tests for modelling.
 """
 import unittest
 from promod3 import modelling
-from ost import conop, seq, io, mol
+from ost import conop, seq, io, mol, geom
 
 class ModellingTests(unittest.TestCase):
+
     def setUp(self):
         compound_lib = conop.CompoundLib.Load(
             'data/compounds.chemlib')
@@ -14,6 +15,28 @@ class ModellingTests(unittest.TestCase):
             compound_lib)
 
     #######################################################################
+    # HELPERs
+    #######################################################################
+    def checkModel(self, mhandle):
+        '''
+        Check if model residues are properly set (peptide_linking, protein,
+        torsion).
+        '''
+        # check residue properties
+        for r in mhandle.model.residues:
+            # check types
+            self.assertTrue(r.peptide_linking)
+            self.assertTrue(r.is_protein)
+            # check links
+            if r.next.IsValid() and (r.next.number - r.number) == 1:
+                self.assertTrue(mol.InSequence(r, r.next))
+            # check torsions
+            if r.prev.IsValid() and mol.InSequence(r.prev, r):
+                self.assertTrue(r.phi_torsion.IsValid())
+                self.assertTrue(r.omega_torsion.IsValid())
+            if r.next.IsValid() and mol.InSequence(r, r.next):
+                self.assertTrue(r.psi_torsion.IsValid())
+    #######################################################################
 
     def testRaiseNoAttachedView(self):
         # test that BuildRawModel throws exception when no view is attached
@@ -123,6 +146,73 @@ class ModellingTests(unittest.TestCase):
 
     #######################################################################
 
+    def testModellingHandleOperations(self):
+        # handle with gap
+        tpl = io.LoadPDB('data/1crn_cut.pdb')
+        aln = io.LoadAlignment('data/1crn.fasta')
+        aln.AttachView(1, tpl.CreateFullView())
+        mhandle = modelling.BuildRawModel(aln)
+
+        # check ModellingHandle
+        self.assertEqual(len(mhandle.gaps), 1)
+        self.assertEqual(str(mhandle.gaps[0]), 'A.ALA24-(ICATYT)-A.GLY31')
+        self.checkModel(mhandle)
+
+        # check copy
+        mhandle_copy = mhandle.Copy()
+        self.assertEqual([str(a) for a in mhandle_copy.model.atoms],
+                         [str(a) for a in mhandle.model.atoms])
+        self.assertEqual([str(g) for g in mhandle_copy.gaps],
+                         [str(g) for g in mhandle.gaps])
+        self.assertEqual([str(s) for s in mhandle_copy.seqres],
+                         [str(s) for s in mhandle.seqres])
+        # rest of the fields not checked...yet
+
+        # handle without gap
+        tpl_closed = io.LoadPDB('data/1crn_build.pdb')
+        seqres = str(aln.sequences[0])
+        aln_closed = seq.CreateAlignment(seq.CreateSequence('trg', seqres),
+                                         seq.CreateSequence('tpl', seqres))
+        aln_closed.AttachView(1, tpl_closed.CreateFullView())
+        mhandle_closed = modelling.BuildRawModel(aln_closed)
+
+        # merge with no overlap (no change)
+        mhandle_copy = mhandle.Copy()
+        modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 10, 19,
+                               geom.Mat4())
+        self.assertEqual([str(a) for a in mhandle_copy.model.atoms],
+                         [str(a) for a in mhandle.model.atoms])
+        self.assertEqual([str(g) for g in mhandle_copy.gaps],
+                         [str(g) for g in mhandle.gaps])
+        self.assertEqual([str(s) for s in mhandle_copy.seqres],
+                         [str(s) for s in mhandle.seqres])
+        self.checkModel(mhandle_copy)
+
+        # merge with overlap on N-side
+        mhandle_copy = mhandle.Copy()
+        modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 20, 29,
+                               geom.Mat4())
+        self.assertEqual(len(mhandle_copy.gaps), 1)
+        self.assertEqual(str(mhandle_copy.gaps[0]), 'A.TYR29-(T)-A.GLY31')
+        self.checkModel(mhandle_copy)
+
+        # merge with overlap on C-side
+        mhandle_copy = mhandle.Copy()
+        modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 27, 35,
+                               geom.Mat4())
+        self.assertEqual(len(mhandle_copy.gaps), 1)
+        self.assertEqual(str(mhandle_copy.gaps[0]), 'A.ALA24-(IC)-A.ALA27')
+        self.checkModel(mhandle_copy)
+
+        # merge with full overlap
+        mhandle_copy = mhandle.Copy()
+        modelling.MergeMHandle(mhandle_closed, mhandle_copy, 0, 0, 20, 35,
+                               geom.Mat4())
+        self.assertEqual(len(mhandle_copy.gaps), 0)
+        self.checkModel(mhandle_copy)
+
+    #######################################################################
+
     def testMergeGaps(self):
         tpl = io.LoadPDB('data/1mcg.pdb')
         aln = seq.CreateAlignment(seq.CreateSequence('trg', 'DDFAGTHN'),