How to do unit testing and how it is different from integration testing in frameworks like Django and fastapi? - django

Let's say I have a Fastapi application like this (This code is taken from documentations):
app = FastAPI()
#app.get("/foo")
async def read_main():
return {"msg": "Hello World"}
I believe there are two ways of testing this view. The first one is by the use of a client object. For instance:
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
However, I think this is not a unit test. It is more like an integration test. Because we are actually running fastapi codes as well.
The second option which in my opinion is closer to unit test definition is to run the function directly:
def test_read_main():
response = read_main()
assert response == {"msg": "Hello World"}
Similarly, in Django, we can directly call the view function, or by using a client object.
My first question is which one is better?
Let's say we chose one of them and now in order to prevent calling the database I have mocked the database. Now I want to test a view that just checks if something exists in the database. My second question is what is the point of testing such view? Becuase after mocking the database, we know what would happen when calling the database with given arguments.

Related

<HttpResponseNotFound status_code=404, "text/html"> in django-test

I'm new to unit testing and I've been trying to test a GET method of the card game that I've built.
My TestCase is the following:
def test_rooms(self):
c = APIClient()
room_id = PokerRoom.objects.get(name='planning').id
request = c.get('http://127.0.0.1:8000/room/{}'.format(room_id))
print(request)
The id is a UUID that's why I'm using the room_id method.
My url:
path('room/<int:pk>', room),
where room is a #api_view(['GET']) method and pk is the id of the room. But when I try to test it, an error occurs:
<HttpResponseNotFound status_code=404, "text/html">
Checked if the room exists in the test database and it exists, now I don't know what is happening. Can someone help me?
Can you add more details to your code above, such as how the test suite has been created, how is the data set up, etc? One problem I am noticing straight away is how the request is being made. Why are you using a complete URL? If you are using the Django/DRF test API client, you should use the view path URL instead of the complete URL.
Reference: https://docs.djangoproject.com/en/4.0/topics/testing/tools/#overview-and-a-quick-example

Testing Graphene-Django

Currently I am investigating using graphene to build my Web server API. I have been using Django-Rest-Framework for quite a while and want to try something different.
I have figured out how to wire it up with my existing project and I can test the query from Graphiql UI, by typing something like
{
industry(id:10) {
name
description
}
}
Now, I want to have the new API covered by Unit/integration tests. And here the problem starts.
All the documentation/post I am checking on testing query/execution on graphene is doing something like
result = schema.execute("{industry(id:10){name, description}}")
assertEqual(result, {"data": {"industry": {"name": "Technology", "description": "blab"}}}
My point is that the query inside execute() is just a big chunk of text and I don't know how I can maintain it in the future. I or other developer in the future has to read that text, figure out what it means and update it if needed.
Is that how this supposed to be? How do you guys write unit test for graphene?
I've been writing tests that do have a big block of text for the query, but I've made it easy to paste in that big block of text from GraphiQL. And I've been using RequestFactory to allow me to send a user along with the query.
from django.test import RequestFactory, TestCase
from graphene.test import Client
def execute_test_client_api_query(api_query, user=None, variable_values=None, **kwargs):
"""
Returns the results of executing a graphQL query using the graphene test client. This is a helper method for our tests
"""
request_factory = RequestFactory()
context_value = request_factory.get('/api/') # or use reverse() on your API endpoint
context_value.user = user
client = Client(schema) # Note: you need to import your schema
executed = client.execute(api_query, context_value=context_value, variable_values=variable_values, **kwargs)
return executed
class APITest(TestCase):
def test_accounts_queries(self):
# This is the test method.
# Let's assume that there's a user object "my_test_user" that was already setup
query = '''
{
user {
id
firstName
}
}
'''
executed = execute_test_client_api_query(query, my_test_user)
data = executed.get('data')
self.assertEqual(data['user']['firstName'], my_test_user.first_name)
...more tests etc. etc.
Everything between the set of ''' s ( { user { id firstName } } ) is just pasted in from GraphiQL, which makes it easier to update as needed. If I make a change that causes a test to fail, I can paste the query from my code into GraphQL, and will often fix the query and paste a new query back into my code. There is purposefully no tabbing on this pasted-in query, to facilitate this repeated pasting.

request issue when unit-testing webapp2 with mock and patch

I'm building unit tests for this webapp2 handler (built for GAE)
class PushNotificationHandler(webapp2.RequestHandler):
def post(self):
UserNotification.parse_from_queue(self.request)
return
app = webapp2.WSGIApplication([
(r'/push/notification', PushNotificationHandler),
], debug=True)
One test is
#patch.object(UserNotification, 'parse_from_queue')
def test_post_webapp(self, p_parse_from_queue):
response = webtest.TestApp(app).post('/push/notification')
eq_(response.status_int, 200)
p_parse_from_queue.assert_called_once_with(response.request)
The HTTP reply is OK, but the mock assertion fails:
Expected call: parse_from_queue(<TestRequest at 0x105a89850 POST http://localhost/push/notification>)
Actual call: parse_from_queue(<Request at 0x105a89950 POST http://localhost/push/notification>)
I can't understand why the request is not the correct one (looks like a deep copy). Is there anything wrong with the unit-test, or is that the way webapp2 handle requests. In the second case, is there a way to test it, without creating a separate test to test PushNotificationHandler.post()
Thanks
I've used mock's call_args in a similar situation. You can do something like this:
request = p_parse_from_queue.call_args[0][0]
self.assertEqual(request.url, "foo")
self.assertEqual(request.*, *)
The [0][0] gives you the first passed argument assuming that you are using ordered arguments and not keyword arguments.
You can then proceed to check other relevant attributes of the request object to make sure it is behaving as expected.

How to mock get_current_user in tornado for unittest?

I have a tornado web application. Many pages require a valid cookie to access. It makes it impossible to test those handlers.
I want to use the mock library to mock the tornado.web.RequestHandler.get_current_user method. But I just cannot get right.
This is how I am doing right now:
class MyUT(tornado.testing.AsyncHTTPTestCase):
def get_app(self):
settings = {
"template_path": '../../../templates',
"cookie_secret": 'secret',
"login_url": '/admin/login',
"debug": True
}
return Application([
(r'/admin/create/super', handlers.CreateSuperUserHandler)
], **settings)
def testGet(self):
with mock.patch.object(handlers.CreateSuperUserHandler, 'get_current_user') as m:
m.return_value = {}
response = self.fetch('/admin/create/super')
print(response.body)
self.assertGreater(response.body.index('create'), 0)
If I execute this code, I got a 404 error. Because I did not define the login hanlder. But I am expecting the mocked get_current_user method return a user object, so do not go to the login page while testing.
One strange thing I found is, if I add m.assert_any_call() in the with block, there's no assertion error.
The #authenticated decorator redirects to the login page if get_current_user returns a falsy value. Try returning a non-empty dict.
You also use handlers.CreateSuperUserHandler in one place and handlers.AdminArea.CreateSuperUserHandler in another; are those the same class object?

Grails 2.1.x Controller Unit Testing with services

Attempting to unit test a Grails 2.1.x controller that calls a template to show a list of history items with a status. This controller works fine in manual testing but were attempting to automate things and I'm getting stuck on this part. Part of our issue may be that the domain object is over engineered.
The setup for this test may be more integration rather than unit testing but I'm not sure I can test the function with out it.
The controller action generates a list of history items via a createCriteria query. This list is passed to the template to be rendered.
def loadHistValues(){
def histDomainObject = new historyDom()
def elements = histDomainObject.createCriteria().list(max: params.max, offset: params.offset)
render (template: 'searchResults', model:[elements: elements]
}
The template has code that iterates through the list putting values in each column. One of these items is getStatus(). This calls a utility service to return the values.
def getStatus(){
return historyUtillityService.getStatus(this)
}
The service gets the latest history event and returns the value.
def getStatus(HistoryDom hist){
def histStatus = HistoryEvent.createCriteria().get(
maxResults(1)
order('id', 'desc')
eq('historyDom', hist)
)
if (histStatus == null)
return 0
else
return histStatus.status
}
I'm getting a null pointer when the getStatus() is called.
I've setup both mock domain object and mock services but I'm not sure that these are getting down to this level or maybe I'm calling them wrong.
#TestFor (HistoryController)
#MockFor (HistoryDom, HistoryEventDom)
class HistoryControllerTests{
def util = new UnitTestUtil()
void testLoadHistValues(){
def mockHistoryUtilityService = mockfor (HistoryUtilityService)
mockHisotryUtilityService.demand.getStatus (-> return Status.QUEUED)
def histObj1 = util.initMockHistObj(1)
def histObj2 = util.initMockHistObj(2)
histObj1.save()
histObj2.save()
def mockHistEvent = new HistEvent(
histDate: histObj1.getHistDate(),
histObj: histObj1,
histStatus: Status.QUEUED
)
mockHistEvent.save()
controller.loadHistValues()
assert response.text contains("Something worth testing")
}
I tried setting a mock view before the call to the controller and checking the response text for that but it never gets past the call to the controller since its still trying to process the template. I'm at a loss at this point as to how to test this controller function, or is it that the object wasn’t architected properly; this seems a bit overly complicated.
answer was to mock things for constrainsts tests before they would get fully saved by mock GORM. I guess mockForConstraintsTests dosnt quite function as I expected