diff --git a/pyverbs/tests/device.py b/pyverbs/tests/device.py
index bdfa81f0dc06..4a5e0a794069 100644
--- a/pyverbs/tests/device.py
+++ b/pyverbs/tests/device.py
@@ -2,10 +2,12 @@
 # Copyright (c) 2018, Mellanox Technologies. All rights reserved.  See COPYING file
 import unittest
 import resource
+import random
 
+from pyverbs.pyverbs_error import PyverbsError, PyverbsRDMAError
+import pyverbs.tests.utils as u
 import pyverbs.device as d
 
-
 PAGE_SIZE = resource.getpagesize()
 
 
@@ -73,3 +75,146 @@ class device_test(unittest.TestCase):
             with d.Context(name=dev.name.decode()) as ctx:
                 attr_ex = ctx.query_device_ex()
                 self.verify_device_attr(attr_ex.orig_attr)
+
+
+class dm_test(unittest.TestCase):
+    """
+    Test various functionalities of the DM class.
+    """
+    def test_create_dm(self):
+        """
+        test ibv_alloc_dm()
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+                                          u.DM_ALIGNMENT)
+                dm_attrs = u.get_dm_attrs(dm_len)
+                with d.DM(ctx, dm_attrs):
+                    pass
+
+    def test_destroy_dm(self):
+        """
+        test ibv_free_dm()
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+                                          u.DM_ALIGNMENT)
+                dm_attrs = u.get_dm_attrs(dm_len)
+                dm = d.DM(ctx, dm_attrs)
+                dm.close()
+
+    def test_create_dm_bad_flow(self):
+        """
+        test ibv_alloc_dm() with an illegal size and comp mask
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = attr.max_dm_size + 1
+                dm_attrs = u.get_dm_attrs(dm_len)
+                try:
+                    dm = d.DM(ctx, dm_attrs)
+                except PyverbsRDMAError as e:
+                    assert 'Failed to allocate device memory of size' in e.args[0]
+                    assert 'Max available size' in e.args[0]
+                else:
+                    raise PyverbsError('Created a DM with size larger than max reported')
+                dm_attrs.comp_mask = random.randint(1, 100)
+                try:
+                    dm = d.DM(ctx, dm_attrs)
+                except PyverbsRDMAError as e:
+                    assert 'Failed to allocate device memory of size' in e.args[0]
+                else:
+                    raise PyverbsError('Created a DM with illegal comp mask {c}'.\
+                                       format(c=dm_attrs.comp_mask))
+
+    def test_destroy_dm_bad_flow(self):
+        """
+        test calling ibv_free_dm() twice
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+                dm_attrs = u.get_dm_attrs(dm_len)
+                dm = d.DM(ctx, dm_attrs)
+                dm.close()
+                dm.close()
+
+    def test_dm_write(self):
+        """
+        Test writing to the device memory
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+                dm_attrs = u.get_dm_attrs(dm_len)
+                with d.DM(ctx, dm_attrs) as dm:
+                    data_length = random.randrange(4, dm_len, u.DM_ALIGNMENT)
+                    data_offset = random.randrange(0, dm_len - data_length, u.DM_ALIGNMENT)
+                    data = u.get_data(data_length)
+                    dm.copy_to_dm(data_offset, data.encode(), data_length)
+
+    def test_dm_write_bad_flow(self):
+        """
+        Test writing to the device memory with bad offset and length
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+                dm_attrs = u.get_dm_attrs(dm_len)
+                with d.DM(ctx, dm_attrs) as dm:
+                    data_length = random.randrange(4, dm_len, u.DM_ALIGNMENT)
+                    data_offset = random.randrange(0, dm_len - data_length, u.DM_ALIGNMENT)
+                    data_offset += 1 # offset needs to be a multiple of 4
+                    data = u.get_data(data_length)
+                    try:
+                        dm.copy_to_dm(data_offset, data.encode(), data_length)
+                    except PyverbsRDMAError as e:
+                            assert 'Failed to copy to dm' in e.args[0]
+                    else:
+                        raise PyverbsError('Wrote to device memory with a bad offset')
+
+    def test_dm_read(self):
+        """
+        Test reading from the device memory
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+                dm_attrs = u.get_dm_attrs(dm_len)
+                with d.DM(ctx, dm_attrs) as dm:
+                    data_length = random.randrange(4, dm_len, u.DM_ALIGNMENT)
+                    data_offset = random.randrange(0, dm_len - data_length, u.DM_ALIGNMENT)
+                    data = u.get_data(data_length)
+                    dm.copy_to_dm(data_offset, data.encode(), data_length)
+                    read_str = dm.copy_from_dm(data_offset, data_length)
+                    assert read_str.decode() == data
diff --git a/pyverbs/tests/mr.py b/pyverbs/tests/mr.py
index c97c6ac38d6d..229da54240cd 100644
--- a/pyverbs/tests/mr.py
+++ b/pyverbs/tests/mr.py
@@ -5,8 +5,8 @@ import random
 
 from pyverbs.pyverbs_error import PyverbsRDMAError, PyverbsError
 from pyverbs.base import PyverbsRDMAErrno
+from pyverbs.mr import MR, MW, DMMR
 import pyverbs.tests.utils as u
-from pyverbs.mr import MR, MW
 import pyverbs.device as d
 from pyverbs.pd import PD
 import pyverbs.enums as e
@@ -181,3 +181,49 @@ class mw_test(unittest.TestCase):
                     else:
                         raise PyverbsError('Created a MW with type {t}'.\
                                            format(t=mw_type))
+
+
+class dm_mr_test(unittest.TestCase):
+    """
+    Test various functionalities of the DMMR class.
+    """
+    def test_create_dm_mr(self):
+        """
+        Test ibv_reg_dm_mr
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                with PD(ctx) as pd:
+                    dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+                                              u.DM_ALIGNMENT)
+                    dm_attrs = u.get_dm_attrs(dm_len)
+                    with d.DM(ctx, dm_attrs) as dm:
+                        dm_mr_len = random.randint(1, dm_len)
+                        dm_mr_offset = random.randint(0, (dm_len - dm_mr_len))
+                        dm_mr = DMMR(pd, dm_mr_len, e.IBV_ACCESS_ZERO_BASED, dm=dm,
+                                     offset=dm_mr_offset)
+
+    def test_destroy_dm_mr(self):
+        """
+        Test freeing of dm_mr
+        """
+        lst = d.get_device_list()
+        for dev in lst:
+            with d.Context(name=dev.name.decode()) as ctx:
+                attr = ctx.query_device_ex()
+                if attr.max_dm_size == 0:
+                    return
+                with PD(ctx) as pd:
+                    dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+                                                             u.DM_ALIGNMENT)
+                    dm_attrs = u.get_dm_attrs(dm_len)
+                    with d.DM(ctx, dm_attrs) as dm:
+                        dm_mr_len = random.randint(1, dm_len)
+                        dm_mr_offset = random.randint(0, (dm_len - dm_mr_len))
+                        dm_mr = DMMR(pd, dm_mr_len, e.IBV_ACCESS_ZERO_BASED, dm=dm,
+                                     offset=dm_mr_offset)
+                        dm_mr.close()
diff --git a/pyverbs/tests/utils.py b/pyverbs/tests/utils.py
index 3281a326b324..c8b46686b0c1 100644
--- a/pyverbs/tests/utils.py
+++ b/pyverbs/tests/utils.py
@@ -2,9 +2,19 @@
 # Copyright (c) 2019, Mellanox Technologies. All rights reserved.  See COPYING file
 from string import ascii_lowercase as al
 import random
+
+import pyverbs.device as d
 import pyverbs.enums as e
 
 MAX_MR_SIZE = 4194304
+# Some HWs limit DM address and length alignment to 4 for read and write
+# operations. Use a minimal length and alignment that respect that.
+# For creation purposes use random alignments. As this is log2 of address
+# alignment, no need for large numbers.
+MIN_DM_SIZE = 4
+DM_ALIGNMENT = 4
+MIN_DM_LOG_ALIGN = 0
+MAX_DM_LOG_ALIGN = 6
 
 def get_mr_length():
     # Allocating large buffers typically fails
@@ -26,3 +36,9 @@ def get_access_flags():
 
 def get_data(length):
     return ''.join(random.choice(al) for i in range(length))
+
+
+def get_dm_attrs(dm_len):
+    align = random.randint(MIN_DM_LOG_ALIGN, MAX_DM_LOG_ALIGN)
+    # Comp mask != 0 is not supported
+    return d.AllocDmAttr(dm_len, align, 0)
