Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests #14

Merged
merged 8 commits into from
Jun 4, 2020
Merged

Add unit tests #14

merged 8 commits into from
Jun 4, 2020

Conversation

hoanhan101
Copy link
Contributor

This PR:

  • Adds unit tests
  • Add a Makefile command test to quickly setup docker-compose and run tests.

Copy link

@edaniszewski edaniszewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Largely looks good. I don't think there is anything major, but I did have a few questions both around intended behaviors and around some of the test setup

def test_list(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 2)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to checking the count, it could be nice to verify that it returns the expected virtual circuit objects

self.assertEqual(response.data['count'], 2)

def test_get_200(self):
response = self.client.get(f'{self.url}{self.vc1.vcid}/')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the trailing / required in the url? if not, it may be good to also test the case with no trailing slash

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Django's URL ends with a / by default, unless set otherwise. Here I am using the defaults so I will need to include the trailing /.

Comment on lines +61 to +64
self.assertEqual(len(response.data), 3)
self.assertIn('vcid', response.data)
self.assertIn('name', response.data)
self.assertIn('vlans', response.data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the expected behavior here? it feels a little strange that a 400 error is returning virtual circuit data. maybe thats intentional/best practice for netbox plugins, but just wanted to verify..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For POST request, these 3 parameters vcid, name, and vlans are required. If they're not provided, it will return a 400 error saying that the missing ones are required ("field_name": "field_value is required"). This check makes sure that the field names are returned in the response.

self.assertEqual(response.data['name'], 'foo')
self.assertEqual(response.data['status'], VirtualCircuitStatusChoices.STATUS_PENDING_CONFIGURATION)
self.assertEqual(response.data['context'], 'bar')
self.assertEqual(len(response.data['vlans']), 0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it valid to be able to create a virtual circuit without any vlans? I thought a virtual circuit required vlans

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's possible to create a virtual circuit without any VLANs. This is actually the initial behavior of the plugin where one needs to create a virtual circuit first then assign VLANs later. Since that takes up 2 requests to do so, #11 allows to create a virtual circuit and assign VLANs at the same time, in a single request.



class VirtualCircuitEndpointTestCase(TestCase):
def setUp(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A somewhat nit-picky/minimal suggestion is that in addition to (or possibly in place of) this setUp block, which runs before every test case, we can consider using setUpClass, which runs once before all tests run. I think that since we are creating the same user/token/client/url for each test, that may be a good place to put it so its only run once.

A second question I have here is whether or not there is a need to define a tearDown function to clean up any of the seed data, either between test cases to ensure each test case starts with the same data, or after the test class completes, to not pollute state for other test classes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been trying to see if I can use setUpClass instead of setup but for some reason, most requests now return a 403 error. I haven't been able to figure out why that's the case so I am opening & tracking an issue and keeping this as it is for now.

On tearDown it seems like test data get cleaned up automatically after each test case. So it might not need to define one.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, interesting. I just noticed that the base class is a django.test.TestCase not a unittest.TestCase, so its pretty likely there is that teardown functionality built in there. It might also be why setUpClass isn't working, if there are some other bits that are going on in the base implementation.

def test_list(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 2)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to checking the count, would be good to verify we get the expected objects as well

self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

class VCVLANEndpointTestCase(TestCase):
def setUp(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same notes as for the previous test case

Comment on lines 25 to 59
def test_get_virtual_circuits(self):
self.assertEqual(self.vc1.vcid, 1)
self.assertEqual(self.vc1.name, 'VC 1')
self.assertEqual(self.vc1.status, VirtualCircuitStatusChoices.STATUS_PENDING_CONFIGURATION)
self.assertEqual(self.vc1.context, '')

self.assertEqual(self.vc2.vcid, 2)
self.assertEqual(self.vc2.name, 'VC 2')
self.assertEqual(self.vc2.status, VirtualCircuitStatusChoices.STATUS_CONFIGURED)
self.assertEqual(self.vc2.context, '')

self.assertEqual(self.vc3.vcid, 3)
self.assertEqual(self.vc3.name, 'VC 3')
self.assertEqual(self.vc3.status, VirtualCircuitStatusChoices.STATUS_PENDING_CONFIGURATION)
self.assertEqual(self.vc3.context, 'foo')

def test_get_vlans(self):
self.assertEqual(self.vlan1.vid, 1)
self.assertEqual(self.vlan1.name, 'VLAN 1')

self.assertEqual(self.vlan2.vid, 2)
self.assertEqual(self.vlan2.name, 'VLAN 2')

self.assertEqual(self.vlan3.vid, 3)
self.assertEqual(self.vlan3.name, 'VLAN 3')

def test_get_virtual_circuits_vlans(self):
self.assertEqual(self.vc1_vlan1.virtual_circuit, self.vc1)
self.assertEqual(self.vc1_vlan1.vlan, self.vlan1)

self.assertEqual(self.vc1_vlan2.virtual_circuit, self.vc1)
self.assertEqual(self.vc1_vlan2.vlan, self.vlan2)

self.assertEqual(self.vc2_vlan3.virtual_circuit, self.vc2)
self.assertEqual(self.vc2_vlan3.vlan, self.vlan3)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally sure what this is testing, as its just verifying the state that was defined in the testcase setup. The name of the test implies that we are testing a "get" capability, but I don't see any getting happening.

If testing the side-effect of the call to create the object, then those calls to create shouldn't be done in the test case setup, but rather in the test case themselves, for the objects applicable to the test



class VirtualCircuitTestCase(TestCase):
def setUp(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar note as above for setUp vs setUpClass

Copy link

@edaniszewski edaniszewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - Thanks for the updates!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants