Sense Functions in Django Based Classes

I am using the Django REST Framework for the API I'm working on. For several reasons, I would like to use class-based views. However, I am a little versed in my unit testing, and I never let my unit tests relate to the database. Note. I always use the β€œtrick” demonstrated by Karl Mayer at Pycon 2012, where he mocks the cursor shell.

cursor_wrapper = Mock() cursor_wrapper.side_effect = RuntimeError("No touching the database!") @patch('django.db.backends.util.CursorWrapper', cursor_wrapper) class TestMyCode(TestCase): 

Here is the link if you are interested in the slide.

I have a method in one of the views that checks something in the database. To be dry, it is distributed between POST and PUT. But I have problems with bullying for my unit test. This is because classmethod as_view creates a new instance and class manager and returns the handler function returned by the send. Thus, I cannot get a generic method in my class based view to mock it.

I can scoff at the models used in the class view, but then I must substantially violate my goal of being β€œDRY” and copy the code in both POST and PUT. I think I could reorganize the code and move the logic to the model. But I'm not sure I want to do this.

How can you use a generic class-based presentation method to avoid actually touching the database? Just avoid them?

+6
source share
1 answer

I think you answered your question. The same things that you use to test any web structure apply to Django, such as inversion of control and dependency injection. You can keep it pretty simple in Python, so don't be alarmed and disable it, like Spring.

Why don't you move the code from the class? Your code will still not be dry if for some reason you need the same logic elsewhere. Just because this Django does not mean that good programming principles do not apply.

I would suggest simply abstracting some things in new python classes / modules, such as services (as a concept, not a definition of Django services) and other logical abstractions for accessing data. Then you are completely independent of the request / response life cycle in the Django view. The trend for Django and Rails developers is that every bit of the logic is directly in the model or view. It just leads to divine classes and things that are hard to verify.

You can also facilitate this by thinking of your presentation as a light abstraction that handles everything related to sorting parameters (GET / POST), etc. with the rest of your code and invoking the necessary logic encapsulated elsewhere. IMO, if you want a testable code, 99% of the logic should be out of the network context, unless that is critical to the process. It also makes it easier to work in the background and in parallel.

As a result, you should use regular python modules and classes that are easy to test, since they do not have direct dependencies on HTTP. If you need to mock HTTP, you can simply make fun of the request object. You are fortunate that the python / django combination makes it easy to dig out and mock these things as simple dicts / kwargs.

One thing that I understood with the help of class-based views is that they are good for using with mixins and enforcing some conventions (returning json, opening graph properties, etc.), but using more "advanced" classes view-based ones that directly require such models since DetailView simply complicates things unnecessarily. These views are good for admin screens, but for real applications, help is more than painful. They do their best to test and kill performance if you don't find a nice, seamless way to integrate caching layers, etc. At the moment, it usually just inherits View or TemplateView and must be executed with it.

When it comes to DB, mocking something, create your own layouts and view your business logic. Then it doesn’t matter what you input / output if it matches a specific set of rules and interfaces. For example, see Mixer . You can also just create / destroy temporary databases during testing. One way is to create separate settings modules for dev / staging / production / testing, etc. And dynamically load them depending on the environment. This way you can avoid damaging your working developers database when doing unit tests. Of course, this is more suitable for the form of integration testing, but you probably should do it too. The above solutions are common in other ORMs such as Hibernate.

According to the previous, you can do something like the code below in your settings to use the in-memory database for unit testing. In the end, however, you still need to consider integration testing against your actual type of data store, e.g. MySQL

 if 'test' in sys.argv: DATABASES['default']['ENGINE'] = 'sqlite3' 

; TL; DR

  • Put your logic outside the class representations in the appropriate objects and modules.

  • Do not block yourself while trying to make various class-related views for working on real applications and in each use case; collapse your own.

  • Use generally good TDD principles, such as IOC, pass the necessary parameters to designers, freely move things, avoid excessive requirements for state requirements (in particular, HTTP).

    • Avoid database dependencies by creating standard mock-up objects (see No. 3) and passing through service interfaces (see No. 1).
+3
source

All Articles