'Mocking complex data structures in Python
I have set of scripts designed to administer a database cluster. I have converted these scripts to an object-oriented design and am having a hell of a time trying to write unit tests. Here's a simplified example of what I'm trying to achieve:
class DBServer:
def __init__(self,hostname):
self.hostname=hostname
def get_instance_status(self):
if (<instance_is_online>):
return True
else:
return false
def shutdown_instance(self):
#<insert code here to stop the DB instance on that node>
class DBCluster:
def __init__(self,clustername):
self.servers=[DBServer('hostname1'), DBServer('hostname2'), DBServer('hostname3'), DBServer('hostname4')]
def get_servers_online(self):
#returns an array of DBServer objects where the DB instance is online
serversonline=[]
for server in self.servers:
if server.get_instance_status():
serversonline.append(server)
return serversonline
def shutdown_cluster(self):
for server in self.servers:
if server.get_instance_status():
server.shutdown_instance()
As you can see, a DBServer is an object with a hostname and some functions that can be run against each server. A DBCluster is an object with an array of DBServers, and some functions that manage the entire cluster.
Imagine a workflow where the user wants to get a list of servers in the cluster where the DB instance is online. Then the user should pick one and shut it down:
def shutdown_user_instance(node_number):
#get list of online instances in cluster, display to user and shut down the chosen instance:
cluster=DBCluster()
servers=cluster.get_servers_online()
print ('Choose server to shut down:')
i=0
for server in servers:
print (str(i) +': ' +server.hostname)
i++
reply=str(input('Option: '))
instance=int(reply)
servers[instance].shutdown_instance()
How do we unit test this function? I'm thinking it should mock the cluster.get_instances_online() function to return an array of mock DBServer objects. I can then create a return value for server.hostname for each object in that array, and then mock server.shutdown_instance(). The trouble is I don't know where to start. Something like this?
class TestCluster(unittest.TestCase):
@patch(stack.DBCluster)
@patch(stack.DBServer)
@patch(builtins.input)
@patch.object(stack.DBserver,'shutdown_instance')
def test_shutdown(self, mock_cluster, mock_server, mock_input, mock_shutdown):
mock_server.get_instance_status.side_effect[True,False,True,False] #for the purpose of this test, let's say nodes 0 and 2 are online, 1 and 3 are offline
mock_cluster.get_servers_online.return_value=[mock_server,mock_server] #How should I achieve this array of mocked objects to test??
mock_input.return_value=0
shutdown_user_instance() #theoretically this should mock a shutdown of node 0
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
