diff --git a/libcloud/common/gandi.py b/libcloud/common/gandi.py
index d27ce3e..25f37e9 100644
--- a/libcloud/common/gandi.py
+++ b/libcloud/common/gandi.py
@@ -23,11 +23,10 @@
 from libcloud.utils.py3 import xmlrpclib
 from libcloud.utils.py3 import b
 
-from libcloud.common.base import ConnectionKey
+from libcloud.common.base import Response, ConnectionKey
 
 # Global constants
 
-API_URL = "https://rpc.gandi.net/xmlrpc/"
 
 DEFAULT_TIMEOUT = 600   # operation pooling max seconds
 DEFAULT_INTERVAL = 20   # seconds between 2 operation.info
@@ -38,65 +37,29 @@ class GandiException(Exception):
     Exception class for Gandi driver
     """
     def __str__(self):
-        return "(%u) %s" % (self.args[0], self.args[1])
+        return '(%u) %s' % (self.args[0], self.args[1])
 
     def __repr__(self):
-        return "<GandiException code %u '%s'>" % (self.args[0], self.args[1])
+        return '<GandiException code %u "%s">' % (self.args[0], self.args[1])
 
 
-class GandiSafeTransport(xmlrpclib.SafeTransport):
-    pass
-
-
-class GandiTransport(xmlrpclib.Transport):
-    pass
-
-
-class GandiProxy(xmlrpclib.ServerProxy):
-    transportCls = (GandiTransport, GandiSafeTransport)
-
-    def __init__(self, user_agent, verbose=0):
-        cls = self.transportCls[0]
-        if API_URL.startswith("https://"):
-            cls = self.transportCls[1]
-        t = cls(use_datetime=0)
-        t.user_agent = user_agent
-        xmlrpclib.ServerProxy.__init__(
-            self,
-            uri=API_URL,
-            transport=t,
-            verbose=verbose,
-            allow_none=True
-        )
-
-
-class GandiConnection(ConnectionKey):
+class GandiResponse(Response):
     """
-    Connection class for the Gandi driver
+    A Base Gandi Response class to derive from.
     """
 
-    proxyCls = GandiProxy
-
-    def __init__(self, key, password=None):
-        super(GandiConnection, self).__init__(key)
-        self.driver = BaseGandiDriver
-
-        try:
-            self._proxy = self.proxyCls(self._user_agent())
-        except xmlrpclib.Fault:
-            e = sys.exc_info()[1]
-            raise GandiException(1000, e)
-
-    def request(self, method, *args):
-        """ Request xmlrpc method with given args"""
+    def parse_body(self):
         try:
-            return getattr(self._proxy, method)(self.key, *args)
+            body, methodname = xmlrpclib.loads(self.body)
+            if len(body) == 1:
+                body = body[0]
+            return body
         except xmlrpclib.Fault:
             e = sys.exc_info()[1]
             self.parse_error(e.faultCode, e.faultString)
-            raise GandiException(1001, e.faultString)
+            raise GandiException(1000, e)
 
-    def parse_error(self, code, message):
+    def parse_error(self, code=None, message=None):
         """
         This hook allows you to inspect any xmlrpclib errors and
         potentially raise a more useful and specific exception.
@@ -104,6 +67,27 @@ def parse_error(self, code, message):
         pass
 
 
+class GandiConnection(ConnectionKey):
+    """
+    Connection class for the Gandi driver
+    """
+
+    responseCls = GandiResponse
+    host = 'rpc.gandi.net'
+
+    def request(self, method, *args):
+        """ Request xmlrpc method with given args"""
+        args = (self.key, ) + args
+        data = xmlrpclib.dumps(args, methodname=method, allow_none=True)
+        headers = {
+            'Content-Type': 'text/xml',
+        }
+        return super(GandiConnection, self).request('/xmlrpc/',
+                                                    data=data,
+                                                    headers=headers,
+                                                    method='POST')
+
+
 class BaseGandiDriver(object):
     """
     Gandi base driver
@@ -112,22 +96,6 @@ class BaseGandiDriver(object):
     connectionCls = GandiConnection
     name = 'Gandi'
 
-    def __init__(self, key, secret=None, secure=False):
-        """
-        @param    key:    API key or username to used (required)
-        @type     key:    C{str}
-
-        @param    secret: Secret password to be used (required)
-        @type     secret: C{str}
-
-        @param    secure: Weither to use HTTPS or HTTP.
-        @type     secure: C{bool}
-        """
-        self.key = key
-        self.secret = secret
-        self.connection = self.connectionCls(key, secret)
-        self.connection.driver = self
-
     # Specific methods for gandi
     def _wait_operation(self, id, timeout=DEFAULT_TIMEOUT,
                         check_interval=DEFAULT_INTERVAL):
@@ -135,7 +103,7 @@ def _wait_operation(self, id, timeout=DEFAULT_TIMEOUT,
 
         for i in range(0, timeout, check_interval):
             try:
-                op = self.connection.request('operation.info', int(id))
+                op = self.connection.request('operation.info', int(id)).object
 
                 if op['step'] == 'DONE':
                     return True
@@ -180,7 +148,7 @@ def get_uuid(self):
         Note, for example, that this example will always produce the
         same UUID!
         """
-        hashstring = "%s:%s:%s" % \
+        hashstring = '%s:%s:%s' % \
             (self.uuid_prefix, self.id, self.driver.type)
         return hashlib.sha1(b(hashstring)).hexdigest()
 
diff --git a/libcloud/compute/drivers/gandi.py b/libcloud/compute/drivers/gandi.py
index a38e211..d9bacea 100644
--- a/libcloud/compute/drivers/gandi.py
+++ b/libcloud/compute/drivers/gandi.py
@@ -62,7 +62,7 @@ def __init__(self, *args, **kwargs):
     def _resource_info(self, type, id):
         try:
             obj = self.connection.request('%s.info' % type, int(id))
-            return obj
+            return obj.object
         except Exception:
             e = sys.exc_info()[1]
             raise GandiException(1003, e)
@@ -109,8 +109,8 @@ def _to_volumes(self, disks):
         return [self._to_volume(d) for d in disks]
 
     def list_nodes(self):
-        vms = self.connection.request('vm.list')
-        ips = self.connection.request('ip.list')
+        vms = self.connection.request('vm.list').object
+        ips = self.connection.request('ip.list').object
         for vm in vms:
             vm['ips'] = []
             for ip in ips:
@@ -124,7 +124,7 @@ def list_nodes(self):
 
     def reboot_node(self, node):
         op = self.connection.request('vm.reboot', int(node.id))
-        self._wait_operation(op['id'])
+        self._wait_operation(op.object['id'])
         vm = self._node_info(int(node.id))
         if vm['state'] == 'running':
             return True
@@ -135,11 +135,11 @@ def destroy_node(self, node):
         if vm['state'] == 'running':
             # Send vm_stop and wait for accomplish
             op_stop = self.connection.request('vm.stop', int(node.id))
-            if not self._wait_operation(op_stop['id']):
+            if not self._wait_operation(op_stop.object['id']):
                 raise GandiException(1010, 'vm.stop failed')
             # Delete
         op = self.connection.request('vm.delete', int(node.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -221,7 +221,7 @@ def create_node(self, **kwargs):
         (op_disk, op_iface, op_vm) = self.connection.request(
             'vm.create_from',
             vm_spec, disk_spec, src_disk_id
-        )
+        ).object
 
         # We wait for vm_create to finish
         if self._wait_operation(op_vm['id']):
@@ -251,7 +251,7 @@ def list_images(self, location=None):
             else:
                 filtering = {}
             images = self.connection.request('image.list', filtering)
-            return [self._to_image(i) for i in images]
+            return [self._to_image(i) for i in images.object]
         except Exception:
             e = sys.exc_info()[1]
             raise GandiException(1011, e)
@@ -268,7 +268,7 @@ def _to_size(self, id, size):
         )
 
     def list_sizes(self, location=None):
-        account = self.connection.request('account.info')
+        account = self.connection.request('account.info').object
         # Look for available shares, and return a list of share_definition
         available_res = account['resources']['available']
 
@@ -306,8 +306,8 @@ def _to_loc(self, loc):
         )
 
     def list_locations(self):
-        res = self.connection.request("datacenter.list")
-        return [self._to_loc(l) for l in res]
+        res = self.connection.request('datacenter.list')
+        return [self._to_loc(l) for l in res.object]
 
     def list_volumes(self):
         """
@@ -315,7 +315,7 @@ def list_volumes(self):
         @rtype: C{list} of L{StorageVolume}
         """
         res = self.connection.request('disk.list', {})
-        return self._to_volumes(res)
+        return self._to_volumes(res.object)
 
     def create_volume(self, size, name, location=None, snapshot=None):
         disk_param = {
@@ -328,15 +328,15 @@ def create_volume(self, size, name, location=None, snapshot=None):
                                          disk_param, int(snapshot.id))
         else:
             op = self.connection.request('disk.create', disk_param)
-        if self._wait_operation(op['id']):
-            disk = self._volume_info(op['disk_id'])
+        if self._wait_operation(op.object['id']):
+            disk = self._volume_info(op.object['disk_id'])
             return self._to_volume(disk)
         return None
 
     def attach_volume(self, node, volume, device=None):
         op = self.connection.request('vm.disk_attach',
                                      int(node.id), int(volume.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -354,13 +354,13 @@ def detach_volume(self, node, volume):
         """
         op = self.connection.request('vm.disk_detach',
                                      int(node.id), int(volume.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
     def destroy_volume(self, volume):
         op = self.connection.request('disk.delete', int(volume.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -401,8 +401,8 @@ def ex_list_interfaces(self):
 
         @rtype: C{list} of L{GandiNetworkInterface}
         """
-        ifaces = self.connection.request('iface.list')
-        ips = self.connection.request('ip.list')
+        ifaces = self.connection.request('iface.list').object
+        ips = self.connection.request('ip.list').object
         for iface in ifaces:
             iface['ips'] = list(
                 filter(lambda i: i['iface_id'] == iface['id'], ips))
@@ -432,7 +432,7 @@ def ex_list_disks(self):
         @rtype: C{list} of L{GandiDisk}
         """
         res = self.connection.request('disk.list', {})
-        return self._to_disks(res)
+        return self._to_disks(res.object)
 
     def ex_node_attach_disk(self, node, disk):
         """
@@ -448,7 +448,7 @@ def ex_node_attach_disk(self, node, disk):
         """
         op = self.connection.request('vm.disk_attach',
                                      int(node.id), int(disk.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -466,7 +466,7 @@ def ex_node_detach_disk(self, node, disk):
         """
         op = self.connection.request('vm.disk_detach',
                                      int(node.id), int(disk.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -485,7 +485,7 @@ def ex_node_attach_interface(self, node, iface):
         """
         op = self.connection.request('vm.iface_attach',
                                      int(node.id), int(iface.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -504,7 +504,7 @@ def ex_node_detach_interface(self, node, iface):
         """
         op = self.connection.request('vm.iface_detach',
                                      int(node.id), int(iface.id))
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -521,16 +521,16 @@ def ex_snapshot_disk(self, disk, name=None):
         @rtype: C{bool}
         """
         if not disk.extra.get('can_snapshot'):
-            raise GandiException(1021, "Disk %s can't snapshot" % disk.id)
+            raise GandiException(1021, 'Disk %s can\'t snapshot' % disk.id)
         if not name:
-            suffix = datetime.today().strftime("%Y%m%d")
-            name = "snap_%s" % (suffix)
+            suffix = datetime.today().strftime('%Y%m%d')
+            name = 'snap_%s' % (suffix)
         op = self.connection.request(
             'disk.create_from',
             {'name': name, 'type': 'snapshot', },
             int(disk.id),
         )
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
 
@@ -557,6 +557,6 @@ def ex_update_disk(self, disk, new_size=None, new_name=None):
         op = self.connection.request('disk.update',
                                      int(disk.id),
                                      params)
-        if self._wait_operation(op['id']):
+        if self._wait_operation(op.object['id']):
             return True
         return False
diff --git a/libcloud/dns/drivers/gandi.py b/libcloud/dns/drivers/gandi.py
index 83f2933..b4419a4 100644
--- a/libcloud/dns/drivers/gandi.py
+++ b/libcloud/dns/drivers/gandi.py
@@ -20,6 +20,7 @@
 ]
 
 from libcloud.common.gandi import BaseGandiDriver, GandiConnection
+from libcloud.common.gandi import GandiResponse
 from libcloud.dns.types import Provider, RecordType
 from libcloud.dns.types import RecordError
 from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError
@@ -51,7 +52,7 @@ def __init__(self, driver, zone):
     def __enter__(self):
         zid = int(self.zone.id)
         self.connection.set_context({'zone_id': self.zone.id})
-        vid = self.connection.request('domain.zone.version.new', zid)
+        vid = self.connection.request('domain.zone.version.new', zid).object
         self.vid = vid
         return vid
 
@@ -60,18 +61,24 @@ def __exit__(self, type, value, traceback):
             zid = int(self.zone.id)
             con = self.connection
             con.set_context({'zone_id': self.zone.id})
-            con.request('domain.zone.version.set', zid, self.vid)
+            con.request('domain.zone.version.set', zid, self.vid).object
 
 
-class GandiDNSConnection(GandiConnection):
+class GandiDNSResponse(GandiResponse):
 
     def parse_error(self, code, message):
+        context = self.connection.context
+        driver = self.connection.driver
         if code == 581042:
-            zone_id = str(self.context.get('zone_id', None))
-            raise ZoneDoesNotExistError(value='', driver=self.driver,
+            zone_id = str(context.get('zone_id', None))
+            raise ZoneDoesNotExistError(value='', driver=driver,
                                         zone_id=zone_id)
 
 
+class GandiDNSConnection(GandiConnection):
+    responseCls = GandiDNSResponse
+
+
 class GandiDNSDriver(BaseGandiDriver, DNSDriver):
     """
     API reference can be found at:
@@ -116,31 +123,33 @@ def _to_zones(self, zones):
 
     def list_zones(self):
         zones = self.connection.request('domain.zone.list')
-        return self._to_zones(zones)
+        return self._to_zones(zones.object)
 
     def get_zone(self, zone_id):
         zid = int(zone_id)
         self.connection.set_context({'zone_id': zid})
         zone = self.connection.request('domain.zone.info', zid)
-        return self._to_zone(zone)
+        return self._to_zone(zone.object)
 
     def create_zone(self, domain, type='master', ttl=None, extra=None):
-        params = {'name': domain}
+        params = {
+            'name': domain,
+        }
         info = self.connection.request('domain.zone.create', params)
-        return self._to_zone(info)
+        return self._to_zone(info.object)
 
     def update_zone(self, zone, domain=None, type=None, ttl=None, extra=None):
         zid = int(zone.id)
         params = {'name': domain}
         self.connection.set_context({'zone_id': zid})
         zone = self.connection.request('domain.zone.update', zid, params)
-        return self._to_zone(zone)
+        return self._to_zone(zone.object)
 
     def delete_zone(self, zone):
         zid = int(zone.id)
         self.connection.set_context({'zone_id': zid})
         res = self.connection.request('domain.zone.delete', zid)
-        return res
+        return res.object
 
     def _to_record(self, record, zone):
         return Record(
@@ -163,7 +172,7 @@ def list_records(self, zone):
         zid = int(zone.id)
         self.connection.set_context({'zone_id': zid})
         records = self.connection.request('domain.zone.record.list', zid, 0)
-        return self._to_records(records, zone)
+        return self._to_records(records.object, zone)
 
     def get_record(self, zone_id, record_id):
         zid = int(zone_id)
@@ -174,7 +183,7 @@ def get_record(self, zone_id, record_id):
         }
         self.connection.set_context({'zone_id': zid})
         records = self.connection.request('domain.zone.record.list',
-                                          zid, 0, filter_opts)
+                                          zid, 0, filter_opts).object
 
         if len(records) == 0:
             raise RecordDoesNotExistError(value='', driver=self,
@@ -212,7 +221,7 @@ def create_record(self, name, zone, type, data, extra=None):
             con = self.connection
             con.set_context({'zone_id': zid})
             rec = con.request('domain.zone.record.add',
-                              zid, vid, create)
+                              zid, vid, create).object
 
         return self._to_record(rec, zone)
 
@@ -241,7 +250,7 @@ def update_record(self, record, name, type, data, extra):
             con.request('domain.zone.record.delete',
                         zid, vid, filter_opts)
             res = con.request('domain.zone.record.add',
-                              zid, vid, update)
+                              zid, vid, update).object
 
         return self._to_record(res, record.zone)
 
@@ -257,7 +266,7 @@ def delete_record(self, record):
             con = self.connection
             con.set_context({'zone_id': zid})
             count = con.request('domain.zone.record.delete',
-                                zid, vid, filter_opts)
+                                zid, vid, filter_opts).object
 
         if count == 1:
             return True
diff --git a/libcloud/test/common/test_gandi.py b/libcloud/test/common/test_gandi.py
index 6352660..d53924d 100644
--- a/libcloud/test/common/test_gandi.py
+++ b/libcloud/test/common/test_gandi.py
@@ -1,33 +1,15 @@
-import sys
-import unittest
-
-from xml.etree import ElementTree as ET
-
 from libcloud.utils.py3 import xmlrpclib
+from libcloud.test import MockHttp
 
 
-class MockGandiTransport(xmlrpclib.Transport):
-
-    def request(self, host, handler, request_body, verbose=0):
-        self.verbose = 0
-        method = ET.XML(request_body).find('methodName').text
-        mock = self.mockCls(host, 80)
-        mock.request('POST', '%s/%s' % (handler, method))
-        resp = mock.getresponse()
-
-        if sys.version[0] == '2' and sys.version[2] == '7':
-            response = self.parse_response(resp)
-        else:
-            response = self.parse_response(resp.body)
-        return response
-
+class BaseGandiMockHttp(MockHttp):
 
-class BaseGandiTests(unittest.TestCase):
+    def _get_method_name(self, type, use_param, qs, path):
+        return "_xmlrpc"
 
-    def setUp(self):
-        d = self.driverCls
-        t = self.transportCls
-        t.mockCls.type = None
-        d.connectionCls.proxyCls.transportCls = \
-            [t, t]
-        self.driver = d(*self.params)
+    def _xmlrpc(self, method, url, body, headers):
+        params, methodName = xmlrpclib.loads(body)
+        meth_name = "_xmlrpc__" + methodName.replace(".", "_")
+        if self.type:
+            meth_name = "%s_%s" % (meth_name, self.type)
+        return getattr(self, meth_name)(method, url, body, headers)
diff --git a/libcloud/test/compute/test_gandi.py b/libcloud/test/compute/test_gandi.py
index ff0e037..f107682 100644
--- a/libcloud/test/compute/test_gandi.py
+++ b/libcloud/test/compute/test_gandi.py
@@ -19,125 +19,26 @@
 import string
 
 from libcloud.utils.py3 import httplib
-from libcloud.utils.py3 import xmlrpclib
 
 from libcloud.compute.drivers.gandi import GandiNodeDriver
-from libcloud.compute.base import StorageVolume
 from libcloud.common.gandi import GandiException
 from libcloud.compute.types import NodeState
 
-from xml.etree import ElementTree as ET
-from libcloud.test import MockHttp
 from libcloud.test.file_fixtures import ComputeFileFixtures
 from libcloud.test.secrets import GANDI_PARAMS
-from libcloud.test.common.test_gandi import MockGandiTransport, BaseGandiTests
+from libcloud.test.common.test_gandi import BaseGandiMockHttp
 
 
-class GandiMockHttp(MockHttp):
-
-    fixtures = ComputeFileFixtures('gandi')
-
-    def _xmlrpc__datacenter_list(self, method, url, body, headers):
-        body = self.fixtures.load('datacenter_list.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__image_list(self, method, url, body, headers):
-        body = self.fixtures.load('image_list_dc0.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_list(self, method, url, body, headers):
-        body = self.fixtures.load('vm_list.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__ip_list(self, method, url, body, headers):
-        body = self.fixtures.load('ip_list.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__account_info(self, method, url, body, headers):
-        body = self.fixtures.load('account_info.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_info(self, method, url, body, headers):
-        body = self.fixtures.load('vm_info.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_delete(self, method, url, body, headers):
-        body = self.fixtures.load('vm_delete.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__operation_info(self, method, url, body, headers):
-        body = self.fixtures.load('operation_info.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_create_from(self, method, url, body, headers):
-        body = self.fixtures.load('vm_create_from.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_reboot(self, method, url, body, headers):
-        body = self.fixtures.load('vm_reboot.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_stop(self, method, url, body, headers):
-        body = self.fixtures.load('vm_stop.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__iface_list(self, method, url, body, headers):
-        body = self.fixtures.load('iface_list.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__disk_list(self, method, url, body, headers):
-        body = self.fixtures.load('disk_list.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_iface_attach(self, method, url, body, headers):
-        body = self.fixtures.load('iface_attach.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_iface_detach(self, method, url, body, headers):
-        body = self.fixtures.load('iface_detach.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_disk_attach(self, method, url, body, headers):
-        body = self.fixtures.load('disk_attach.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__vm_disk_detach(self, method, url, body, headers):
-        body = self.fixtures.load('disk_detach.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__disk_create(self, method, url, body, headers):
-        body = self.fixtures.load('disk_create.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__disk_create_from(self, method, url, body, headers):
-        body = self.fixtures.load('disk_create_from.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__disk_info(self, method, url, body, headers):
-        body = self.fixtures.load('disk_info.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__disk_update(self, method, url, body, headers):
-        body = self.fixtures.load('disk_update.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__disk_delete(self, method, url, body, headers):
-        body = self.fixtures.load('disk_delete.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-
-class DummyTransport(MockGandiTransport):
-    mockCls = GandiMockHttp
-
-
-class GandiTests(BaseGandiTests):
-
-    driverCls = GandiNodeDriver
-    transportCls = DummyTransport
-    params = GANDI_PARAMS
+class GandiTests(unittest.TestCase):
 
     node_name = 'test2'
 
+    def setUp(self):
+        GandiNodeDriver.connectionCls.conn_classes = (
+            GandiMockHttp, GandiMockHttp)
+        GandiMockHttp.type = None
+        self.driver = GandiNodeDriver(*GANDI_PARAMS)
+
     def test_list_nodes(self):
         nodes = self.driver.list_nodes()
         self.assertTrue(len(nodes) > 0)
@@ -254,5 +155,98 @@ def test_ex_update_disk(self):
         self.assertTrue(self.driver.ex_update_disk(disks[0], new_size=4096))
 
 
+class GandiMockHttp(BaseGandiMockHttp):
+
+    fixtures = ComputeFileFixtures('gandi')
+
+    def _xmlrpc__datacenter_list(self, method, url, body, headers):
+        body = self.fixtures.load('datacenter_list.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__image_list(self, method, url, body, headers):
+        body = self.fixtures.load('image_list_dc0.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_list(self, method, url, body, headers):
+        body = self.fixtures.load('vm_list.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__ip_list(self, method, url, body, headers):
+        body = self.fixtures.load('ip_list.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__account_info(self, method, url, body, headers):
+        body = self.fixtures.load('account_info.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_info(self, method, url, body, headers):
+        body = self.fixtures.load('vm_info.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_delete(self, method, url, body, headers):
+        body = self.fixtures.load('vm_delete.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__operation_info(self, method, url, body, headers):
+        body = self.fixtures.load('operation_info.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_create_from(self, method, url, body, headers):
+        body = self.fixtures.load('vm_create_from.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_reboot(self, method, url, body, headers):
+        body = self.fixtures.load('vm_reboot.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_stop(self, method, url, body, headers):
+        body = self.fixtures.load('vm_stop.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__iface_list(self, method, url, body, headers):
+        body = self.fixtures.load('iface_list.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__disk_list(self, method, url, body, headers):
+        body = self.fixtures.load('disk_list.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_iface_attach(self, method, url, body, headers):
+        body = self.fixtures.load('iface_attach.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_iface_detach(self, method, url, body, headers):
+        body = self.fixtures.load('iface_detach.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_disk_attach(self, method, url, body, headers):
+        body = self.fixtures.load('disk_attach.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__vm_disk_detach(self, method, url, body, headers):
+        body = self.fixtures.load('disk_detach.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__disk_create(self, method, url, body, headers):
+        body = self.fixtures.load('disk_create.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__disk_create_from(self, method, url, body, headers):
+        body = self.fixtures.load('disk_create_from.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__disk_info(self, method, url, body, headers):
+        body = self.fixtures.load('disk_info.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__disk_update(self, method, url, body, headers):
+        body = self.fixtures.load('disk_update.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__disk_delete(self, method, url, body, headers):
+        body = self.fixtures.load('disk_delete.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+
 if __name__ == '__main__':
     sys.exit(unittest.main())
diff --git a/libcloud/test/dns/fixtures/gandi/zone_doesnt_exist.xml b/libcloud/test/dns/fixtures/gandi/zone_doesnt_exist.xml
new file mode 100644
index 0000000..c9f245d
--- /dev/null
+++ b/libcloud/test/dns/fixtures/gandi/zone_doesnt_exist.xml
@@ -0,0 +1,17 @@
+<?xml version='1.0'?>
+<methodResponse>
+  <fault>
+    <value>
+      <struct>
+        <member>
+          <name>faultCode</name>
+          <value><int>581042</int></value>
+        </member>
+        <member>
+          <name>faultString</name>
+          <value><string>Zone does not exist</string></value>
+        </member>
+      </struct>
+    </value>
+  </fault>
+</methodResponse>
diff --git a/libcloud/test/dns/test_gandi.py b/libcloud/test/dns/test_gandi.py
index 03b7559..b9a5d62 100644
--- a/libcloud/test/dns/test_gandi.py
+++ b/libcloud/test/dns/test_gandi.py
@@ -17,106 +17,21 @@
 import unittest
 
 from libcloud.utils.py3 import httplib
-from libcloud.utils.py3 import xmlrpclib
 from libcloud.dns.types import RecordType, ZoneDoesNotExistError
 from libcloud.dns.types import RecordDoesNotExistError
 from libcloud.dns.drivers.gandi import GandiDNSDriver
-from libcloud.test import MockHttp
 from libcloud.test.file_fixtures import DNSFileFixtures
 from libcloud.test.secrets import DNS_GANDI
-from libcloud.test.common.test_gandi import MockGandiTransport, BaseGandiTests
+from libcloud.test.common.test_gandi import BaseGandiMockHttp
 
-Fault = xmlrpclib.Fault
 
-class GandiMockHttp(MockHttp):
-    fixtures = DNSFileFixtures('gandi')
-
-    def _xmlrpc__domain_zone_create(self, method, url, body, headers):
-        body = self.fixtures.load('create_zone.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_update(self, method, url, body, headers):
-        body = self.fixtures.load('get_zone.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_list(self, method, url, body, headers):
-        body = self.fixtures.load('list_zones.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_record_list(self, method, url, body, headers):
-        body = self.fixtures.load('list_records.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_record_add(self, method, url, body, headers):
-        body = self.fixtures.load('create_record.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_delete(self, method, url, body, headers):
-        body = self.fixtures.load('delete_zone.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_info(self, method, url, body, headers):
-        body = self.fixtures.load('get_zone.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_record_delete(self, method, url, body, headers):
-        body = self.fixtures.load('delete_record.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_record_update(self, method, url, body, headers):
-        body = self.fixtures.load('create_record.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_version_new(self, method, url, body, headers):
-        body = self.fixtures.load('new_version.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_version_set(self, method, url, body, headers):
-        body = self.fixtures.load('new_version.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_record_list_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
-        raise Fault(581042, "Zone does not exist")
-
-    def _xmlrpc__domain_zone_info_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
-        raise Fault(581042, "Zone does not exist")
+class GandiTests(unittest.TestCase):
 
-    def _xmlrpc__domain_zone_list_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
-        raise Fault(581042, "Zone does not exist")
-
-    def _xmlrpc__domain_zone_delete_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
-        raise Fault(581042, "Zone does not exist")
-
-    def _xmlrpc__domain_zone_record_list_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
-        body = self.fixtures.load('list_records_empty.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_info_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
-        body = self.fixtures.load('list_zones.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_record_delete_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
-        body = self.fixtures.load('delete_record_doesnotexist.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_version_new_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
-        body = self.fixtures.load('new_version.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-    def _xmlrpc__domain_zone_version_set_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
-        body = self.fixtures.load('new_version.xml')
-        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-
-
-class DummyTransport(MockGandiTransport):
-    mockCls = GandiMockHttp
-
-
-class GandiTests(BaseGandiTests):
-
-    driverCls = GandiDNSDriver
-    transportCls = DummyTransport
-    params = DNS_GANDI
+    def setUp(self):
+        GandiDNSDriver.connectionCls.conn_classes = (
+            GandiMockHttp, GandiMockHttp)
+        GandiMockHttp.type = None
+        self.driver = GandiDNSDriver(*DNS_GANDI)
 
     def test_list_record_types(self):
         record_types = self.driver.list_record_types()
@@ -285,5 +200,88 @@ def test_delete_record_does_not_exist(self):
             self.fail('Exception was not thrown')
 
 
+class GandiMockHttp(BaseGandiMockHttp):
+    fixtures = DNSFileFixtures('gandi')
+
+    def _xmlrpc__domain_zone_create(self, method, url, body, headers):
+        body = self.fixtures.load('create_zone.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_update(self, method, url, body, headers):
+        body = self.fixtures.load('get_zone.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_list(self, method, url, body, headers):
+        body = self.fixtures.load('list_zones.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_list(self, method, url, body, headers):
+        body = self.fixtures.load('list_records.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_add(self, method, url, body, headers):
+        body = self.fixtures.load('create_record.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_delete(self, method, url, body, headers):
+        body = self.fixtures.load('delete_zone.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_info(self, method, url, body, headers):
+        body = self.fixtures.load('get_zone.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_delete(self, method, url, body, headers):
+        body = self.fixtures.load('delete_record.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_update(self, method, url, body, headers):
+        body = self.fixtures.load('create_record.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_version_new(self, method, url, body, headers):
+        body = self.fixtures.load('new_version.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_version_set(self, method, url, body, headers):
+        body = self.fixtures.load('new_version.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_list_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('zone_doesnt_exist.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_info_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('zone_doesnt_exist.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_list_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('zone_doesnt_exist.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_delete_ZONE_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('zone_doesnt_exist.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_list_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('list_records_empty.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_info_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('list_zones.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_record_delete_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('delete_record_doesnotexist.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_version_new_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('new_version.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc__domain_zone_version_set_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('new_version.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
 if __name__ == '__main__':
     sys.exit(unittest.main())
