Unit test an external facing function - django

I am trying to write unit test case for an external facing api of my Django application. I have a model called Dummy with two fields temp and content. The following function is called by third party to fetch the content field. temp is an indexed unique key.
#csrf_exempt
def fetch_dummy_content(request):
try:
temp = request.GET.get("temp")
dummy_obj = Dummy.objects.get(temp=temp)
except Dummy.DoesNotExist:
content = 'Object not found.'
else:
content = dummy_obj.content
return HttpResponse(content, content_type='text/plain')
I have the following unit test case.
def test_dummy_content(self):
params = {
'temp': 'abc'
}
dummy_obj = mommy.make(
'Dummy',
temp='abc',
content='Hello World'
)
response = self.client.get(
'/fetch_dummy_content/',
params=params
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, 'Hello World')
Every time I run the test case, it goes into exception and returns Object not found. instead of Hello World. Uponn further debugging I found that temp from request object inside view function is always None, even though I am passing it in params.
I might be missing something and not able to figure out. What's the proper way to test these kind of functions.

There's no params parameter for the get or any of the other functions on the client, you're probably thinking of data.
response = self.client.get(
'/fetch_dummy_content/',
data=params
)
It's the second argument anyway, so you can just do self.client.get('/fetch_dummy_content/', params) too.
Any unknown parameters get included in the environment which explains why you were not getting an error for using the wrong name.

Related

Pyral Cannot Parse Parent Object returned

I am trying to get the Parent Epic / Feature for particular User Stories in Rally. However I am only getting the parent object and I am not sure how to parse it. I have tried dict and dir(object) to get field values but it did not work. I have also tried as following, but I keep on getting something like this instead of fields/values in Parent Object
pyral.entity.PortfolioItem_Capability object at 0x7ff848273850
CODE:
def get_hierarchy(server,username,password,workspace,project,release):
rally = Rally(server, username, password, workspace=workspace, project=project)
criterion = 'Release.Name = "'+release+'" AND Parent != None'
response = rally.get('HierarchicalRequirement',fetch="ObjectID,FormattedID,Name,AcceptedDate,Project,Release,ScheduleState,Parent,Description",query=criterion,limit=5000)
return response
for item in get_hierarchy("rally1.rallydev.com","some.email#address.com","Somepassword","Some Workspace Name","PROJECT NAME","Release Version"):
print item.FormattedID, item.Name, item.ScheduleState, item.Description, item.Parent.Name
The parent is also an object and you have to parse the parent similar to the user story. For a simplistic solution, keep using the dot format. Here is a code snippet that does something similar to the above that should give you a start.
queryString = '(Iteration.StartDate > "2017-08-31")'
entityName = 'HierarchicalRequirement'
response = rally.get(entityName, fetch=True, projectScopeDown=True, query=queryString)
for item in response:
print(item.FormattedID,
item.PortfolioItem.FormattedID,
item.PortfolioItem.Parent.FormattedID,
item.PlanEstimate)
I'm using Python 3.x but I don't see any reason it wouldn't translate to 2.7.

Additional arguments in Flask grequests hook

I am having issue in passing additional parameter to grequests using a hook, Its working in a standalone app (non flask) but its not with flask (flask integrated server) Here is my code snippet.
self.async_list = []
for url in self.urls:
self.action_item = grequests.get(url, hooks = {'response' : [self.hook_factory(test='new_folder')]}, proxies={ 'http': 'proxy url'},timeout=20)
self.async_list.append(self.action_item)
grequests.map(self.async_list)
def hook_factory(self, test, *factory_args, **factory_kwargs):
print (test + "In start of hook factory") #this worked and I see test value is printing as new_folder
def do_something(response, *args, **kwargs):
print (test + "In do something") #This is not working hence I was not able to save this response to a newly created folder.
self.file_name = "str(test)+"/"
print ("file name is " + self.file_name)
with open(REL_PATH + self.file_name, 'wb') as f:
f.write(response.content)
return None
return do_something
Am I missing anything here?.
Trying to answer my own question, After further analysis there was nothing wrong with the above code, for some reason I was not getting my session data which is in the request_ctx_stack.top. But the same session data was available in my h_request_ctx_stack._local, Don't know the reason. But I was able to get my data from h_request_ctx_stack._local instead _request_ctx_stack.top for this hook alone. After I made that change was able execute the same hook without any issues.

Having difficulty mocking object returned by patched function

I have an instance method on a Django form class that returns a Python object from a payment service if successful.
The object has an id property, which I then persist on a Django model instance.
I'm having some difficulty getting the mocked object to return its .id property correctly.
# tests.py
class DonationFunctionalTest(TestCase):
def test_foo(self):
with mock.patch('donations.views.CreditCardForm') as MockCCForm:
MockCCForm.charge_customer.return_value = Mock(id='abc123')
# The test makes a post request to the view here.
# The view being tested calls:
# charge = credit_card_form.charge_customer()
# donation.charge_id = charge.id
# donation.save()
However:
print donation.charge_id
# returns
u"<MagicMock name='CreditCardForm().charge_customer().id'
I expected to see "abc123" for the donation.charge_id, but instead I see a unicode representation of the MagicMock. What am I doing wrong?
Got it working by doing the patching a bit differently:
#mock.patch('donations.views.CreditCardForm.create_card')
#mock.patch('donations.views.CreditCardForm.charge_customer')
def test_foo(self, mock_charge_customer, mock_create_card):
mock_create_card.return_value = True
mock_charge_customer.return_value = MagicMock(id='abc123')
# remainder of code
Now the id matches what I expect. I'd still like to know what I did wrong on the previous code though.

TDD Django tests seem to skip certain parts of the view code

I'm writing some tests for a site using django TDD.
The problem is that when I manually go to the testserver. Fill in the form and submit it then it seems to works fine. But when I run the test using manage.py test wiki it seems to skip parts of the code within the view. The page parts all seem to work fine. But the pagemod-parts within the code and even a write() I created just to see what was going on seems to be ignored.
I have no idea what could be causing this and can't seem to find a solution. Any ideas?
This is the code:
test.py
#imports
class WikiSiteTest(LiveServerTestCase):
....
def test_wiki_links(self):
'''Go to the site, and check a few links'''
#creating a few objects which will be used later
.....
#some code to get to where I want:
.....
#testing the link to see if the tester can add pages
link = self.browser.find_element_by_link_text('Add page (for testing only. delete this later)')
link.click()
#filling in the form
template_field = self.browser.find_element_by_name('template')
template_field.send_keys('homepage')
slug_field = self.browser.find_element_by_name('slug')
slug_field.send_keys('this-is-a-slug')
title_field = self.browser.find_element_by_name('title')
title_field.send_keys('this is a title')
meta_field = self.browser.find_element_by_name('meta_description')
meta_field.send_keys('this is a meta')
content_field = self.browser.find_element_by_name('content')
content_field.send_keys('this is content')
#submitting the filled form so that it can be processed
s_button = self.browser.find_element_by_css_selector("input[value='Submit']")
s_button.click()
# now the view is called
and a view:
views.py
def page_add(request):
'''This function does one of these 3 things:
- Prepares an empty form
- Checks the formdata it got. If its ok then it will save it and create and save
a copy in the form of a Pagemodification.
- Checks the formdata it got. If its not ok then it will redirect the user back'''
.....
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
user = request.user.get_profile()
page = form.save(commit=False)
page.partner = user.partner
page.save() #works
#Gets ignored
pagemod = PageModification()
pagemod.template = page.template
pagemod.parent = page.parent
pagemod.page = Page.objects.get(slug=page.slug)
pagemod.title = page.title
pagemod.meta_description = page.meta_description
pagemod.content = page.content
pagemod.author = request.user.get_profile()
pagemod.save()
f = open("/location/log.txt", "w", True)
f.write('are you reaching this line?')
f.close()
#/gets ignored
#a render to response
Then later I do:
test.py
print '###############Data check##################'
print Page.objects.all()
print PageModification.objects.all()
print '###############End data check##############'
And get:
terminal:
###############Data check##################
[<Page: this is a title 2012-10-01 14:39:21.739966+00:00>]
[]
###############End data check##############
All the imports are fine. Putting the page.save() after the ignored code makes no difference.
This only happens when running it through the TDD test.
Thanks in advance.
How very strange. Could it be that the view is somehow erroring at the Pagemodification stage? Have you got any checks later on in your test that assert that the response from the view is coming through correctly, ie that a 500 error is not being returned instead?
Now this was a long time ago.
It was solved but the solution was a little embarrassing. Basically, it was me being stupid. I can't remember the exact details but I believe a different view was called instead of the one that I showed here. That view had the same code except the "skipped" part.
My apologies to anyone who took their time looking into this.

Deleting object in django and API call

I am trying to delete a client object in my program and then also delete the object in activeCollab using the API provided. I can delete the object but I keep getting a 404 error when it calls the API. I did a print for c.id and I am getting the correct ID, and if I replace ':company_id' in the req statement with the actual ID of the client, it works.
Here is my code for the delete:
def deleteClient(request, client_id):
c = get_object_or_404(Clients, pk = client_id)
#adding the params for the request to the aC API
params = urllib.urlencode({
'submitted':'submitted',
'company[id]': c.id,
})
#make the request
req = urllib2.Request("http://website_url/public/api.php?path_info=/people /:company_id/delete&token=XXXXXXXXXXXXXXXXXXXX", params)
f = urllib2.urlopen(req)
print f.read()
c.delete()
return HttpResponseRedirect('/clients/')
Thanks everyone.
Oh here is the link to the API documentation for the delete:
http://www.activecollab.com/docs/manuals/developers/api/companies-and-users
From the docs it appears that :company_id is supposed to be replaced by the actual company id. This replacement won't happen automatically. Currently you are sending the company id in the POST parameters (which the API isn't expecting) and you are sending the literal value ':company_id' in the query string.
Try something like:
url_params=dict(path_info="/people/%s/delete" % c.id, token=MY_API_TOKEN)
data_params=dict(submitted=submitted)
req = urllib2.Request(
"http://example.com/public/api.php?%s" % urllib.urlencode(url_params),
urllib.urlencode(data_params)
)
Of course, because you are targeting this api.php script, I can't tell if that script is supposed to do some magic replacement. But given that it works when you manually replace the :company_id with the actual value, this is the best bet, I think.