Practical Unit Testing in Django
Merry, Wayne
This talk is an opportunity for you to explore practical ways of improving the test code you write. Unit testing can be challenging, but with the right toolbox of techniques, it is much easier to write unit tests that not only enable high degrees of code coverage, but assurance on each action of your code. Django provides an excellent test environment that facilitates testing across the whole of a project, however Django’s documentation and many online examples focus on integration tests. Any typical use of the Django test client is an integration test. Tools such as selenium also provide a frame work for usability tests, functional tests or integration tests. What is missing in this is a close look at unit tests. It is difficult to obtain high code coverage with integration tests alone. This talk will build on Daniel Davis’ DjangoCon2015 talk “Why Unit Testing Doesn’t Have To Be So Hard”. That talk introduced the concept of using mocking to deal with the complexity of unit testing and gave a number of simple examples. In this talk, we will apply mocking, dummy objects and harnesses to unit test in the Django environment. We will focus first on class based views. Django provides an extensive Generic Class Base View hierarchy of base classes and mixins. These define a series of methods that focus on various elements of the response process. For more complex applications, this system provides much of what is needed but often customizations are needed and these can take the form of subclasses overriding one or more methods, or perhaps mixins that are built to implement abstractions of these customizations. In order to unit test these customizations, we want to place each individual method under test. To obtain strong assurance of code performance, we want to place under test each action of the code, plus its coupling with its base class(es). A test harness, mocks and dummy objects all assist in this process and we will explore examples of such. Mocks particularly facilitate our tests by us being able assert on what is passed on other method calls and on the super() call. Mixins are used to implement customization abstractions. Their methods can be unit tested making use of dummy subclasses. Form classes also benefit from unit testing. Form classes may define clean methods for validation, and these clean methods can be called directly in unit tests for both valid and invalid data. Some modelform classes may implement business logic in their save() methods and these also highly benefit from unit testing. Both forms and views often make use of the ORM. When performing integration testing, this often means setting up test fixtures, but for unit testing it might be much more efficient to mock out ORM calls such as filter(), all(), count(), etc. Sometimes code under test will chain these ORM functions and this also can be mocked. We will then consider a more complex example of a view that makes use of an inlineformset. inlineformsets are more complex form objects, but various approaches can be used to unit test views that make use of formsets (along with unit tests of the formset itself). We will close with some template unit testing. The content of this talk is built on examples taken from real systems implementation. These should give many Django practitioners a boost in their day to day testing toolkit.
 Thank you for coming. Can you all hear me? I don't know if I'll back here. So today we're going to look at practical unit testing in Django. If you went to the testing talk yesterday, we're going to dive into it in more detail, specifically about unit testing rather than general Django testing. So if you've not done mocking before, a good intro talk is from DjangoCon US 2015, while unit testing doesn't have to be so hard. That's when my introduction to mocking happened then, and then using that in a Django context and a few tears later, then we've sort of developed some techniques. So that's definitely a good talk to check out if you're new to this area. And so what we're covering is we're covering unit testing. We're going to look at some examples of testing with views, forms, fields, and some template tags. We're not covering integration testing, so I'm not going to get into whether you should use or not use mocks when it comes to those things that much, apart from stating a personal opinion. I never use mocks in integration tests. I can avoid it anyway, but they're essential when it comes to unit tests. So why unit tests? I started by Django Adventure by doing the tutorial. And the tutorial has a section on testing. That section on testing is integration testing. Now the problem is as a project grows in scope, it becomes very hard to get a high level of code coverage using the Django test client, where the code that you're trying to test might be 20 method calls down the tree. And so that doesn't really work in terms of really exploring the code that you're placing under test in a particular module. So we need a more direct way of attacking what we're trying to test rather than trying to test the whole stack. In a project, you would do integration testing. So those tests are still there. But then you... So there's a percentage of tests that are integration and functional tests, but a whole lot of tests are going to be unit tests. There's many dependencies that can exist in a project. This can often be more than just take what the parameters that come in and a result that comes out. There's side effects. There's classes. There's attributes of classes. You might be changing those attributes of classes. And so those things are side effects and they increase the complexity of testing. And so we need a way of getting some sanity about all this because that kind of drives you crazy. And sometimes really it can be so complicated it can just not be even plausible to try and manage it at such a high level. So what is a unit test? The idea is to place one method under test. And you're testing the internal operation of that method. You're testing how it calls other methods. And you're looking at what it does when it gets the results of other methods back and what it might do with that, which might be simply just returning it onwards. Then you presume everything else is reliable. So Python's duck place typing. So can you tell me a bit of interaction here? What is that animal that we see on the screen? Oh, we don't see anything on the screen at all now. Hopefully that stays there. I'm not going to touch anything. So the point is it doesn't really matter what is the big picture of what you're testing. You are testing a method. So we've got the nose of a duck, a little toy duck on this line. It doesn't matter the thing is a line. You're just testing that narrow bit with a nose, that red nose. And so long as that does, you only need to do enough to make it work in the context of your method. Everything else that it does doesn't really matter. And I'll fill that out in some details as we go along. But to get you thinking, if you're testing some code that takes an OOM result and you're say adding something to it, you actually don't need the OOM to test what you are doing. The OOM itself is out of scope of your particular method. And we'll have a look at some examples. The point is if you're testing just at that red nose, that's all that matters. Everything else is irrelevant. So our first domain that we want to talk about is testing class-based views. If you're using functional views, I don't really use them anymore. So I'm going to be focused on class-based views. Now, class-based views, there's a big hierarchy and there's lots of methods in there. What then typically happens is you might be inheriting from, say, Create View or Update View and you might be defining a few methods that add to that. Just do a few things extra, maybe just one line of code extra. What you're testing is that one line of code and the call to the super function and the result that comes back. And that's all you're testing. You're not testing anything else. So what we... So as the slide talks about, each override that you make is going to be a method that you...that you're either deriving from the class and writing a specific override or perhaps you've noticed you've done that a few times and so now it's time for a mix-in. And so we're going to define a mix-in that does one or two things in one or two methods and we want to test that. So what we want to do is we want to test those methods. Now what we don't want to do is we don't want to call the Django test client because that's an integration test and that relies on the whole Kicking a Boot or to be there and we don't really want that. So what we need to do is we need to basically create enough of our view in memory so we can call the function we actually want to test. And so the top function there is a function that just rips out a little bit of from the as view function that's from the Django class-based view hierarchy to set up a test object, a view object, I should say. So it sets up the attributes for request args and key words and returns the view. If you look at as view in the Django source code you'll notice that that exists in there. It does a few other things but they're not really needed for our unit test. And then to actually test this thing in the setup function in the test class we see that we go to the request factory. That was the existence of the request factory as talked about yesterday. In this case we're testing a get method but that could be other HTTP methods. It doesn't really matter what URL you give it. You don't need to worry about URL resolving. You can call it ABC. It's really irrelevant. Just feed it some string. We create our view which is the view under test and we call that method that's up the top. And that sets up the view and then what we can do is we can directly call the method. If our class under test has got say a dispatch method override then we can just directly call that by going view.dispatch with the request and any arguments, keyword arguments. So we can directly call that method and we don't need to worry about everything else that goes with it. If we're common functions to override is get context data. You just call it directly with a dictionary as your keyword args and then you look at what it does inside. So moving on to forms. So we want to test the idea is to test every action of a method to get some kind of assurance that this code is going to do what it does. So here's a function we want to test. It's the clean method of a form and what it does is it's testing two dates and if the end date is after the start date we just want to make it the same as we want to make the start date the same as the end date. So if the start dates later. So it doesn't do that or not. And if there's an exception then we want that not, we want it to basically do nothing. So here are two tests that do that. So we haven't looked at what they do. The first thing is they patch the clean method that's inherited. The super call is going to call the form clean method. We actually don't want to call the form clean method because we're not interested in testing what that does. We just want, so we need to patch that. And so your suspect means it'll test whether we're calling it in the way that it will be expected and then we give it a result value. We're just going to give it a result of ABC. We call it whatever we want. And then so then the method, the first line is it creates the form. Form equals self test form. Then it sets up some clean data. Now when you're doing an integration test that's already done somewhere else but we're just going to be calling clean. So clean data doesn't exist. So we need to make that. That's a dependency. So we need to set that up and we'll put some clean data in there. The first one there is no end date so that would throw an exception. We're testing for only a start date. Then it says result equals form clean. It calls the clean method directly. Then it looks at what comes out. The first assertion is did it call the super method? Did that clean method of the form get called? And was it called once? Which is what we expect. The previous method has got one called a super. What happens if we made a coding error and we called it twice? Well then the assertion will fail. Then the next line is it asserts that clean data has only got a start date in it. There's no end date that appeared because our code is not supposed to do that. Now if I wanted to pass it, if I wanted to throw the exception and not capture it, I could use an assertion called assert raises and put the exception in there. Then the test will pass if an exception is thrown that's not captured. So I can, whether I need to throw the exception or not, I can test specifically for that. Then the final thing is this last assertion is the result ABC. We go back and have a look at the code. The result from super is put into a variable called result and then down the bottom return result. If I leave that bottom line out to get to return the result, then that final assertion will fail. So I am testing, it's my method that takes the result of the super call and will pass that out to the caller. I want to test that. That's something that my method is doing. So anything that my method is doing, I want to test that. And that's what that final assertion, the set result ABC needs to test. If I change the return value back on the patch at the top line to D E F, then my assertion will fail unless I test for D E F. So that's the concept of detailed unit testing. So going on, let's just talking about this at a more conceptual level. So methods do things. And we want to try and capture each thing that it does. So some of it is direct in method actions such as assignments or doing some sort of mathematics or whatever. And the other thing that they typically do is call stuff. And most often, but not always, that's a call to super. But sometimes it's a call to other things. Whatever it calls, you want to test that it's calling it as you expect it will call it, given the inputs that you're feeding to this function. If you say if you only sometimes call super based on certain inputs, then you'll want test case that test for the domain of inputs that should call super. And then for the ones that shouldn't call super, you'll be looking that it's call count is zero. Now as soon as you introduce an if statement, you've got a code branch. And so that's likely to mean more than one test case. So you can test each branch. If you're getting too many of them and you're getting a whole pile of test cases, that's a prime indication that you need to break the thing up. Just a few notes on in the Python mock library has this thing called call args and call args lists. So to save you a bit of blood, sweat and tears, the first index element contains all the positional arguments. It's not just stuff that you put in star args, but anything that's called as a positional argument. The second index is anything that you call as a keyword args. If the thing is a method that's on an object, self will be the first positional argument. But if it is a class method, class is not passed as a positional argument, even though you put it in the code, because Python already knows the name of the class. So class is actually not passed as the first positional keyword, so first positional arg, you know you actually physically write CLS or whatever you want to call it in the code. And if it's a static method where you're expecting nothing to be passed at that stage, call args list is used when you're calling the function more than once. It allows you to make assertions on the parameters for each call. So next thing is mixins. So we discussed the mixins a little bit before. So if you write a mixin and you be wanting to test its method, so in this case we've got a validation object which is designed, it's a mixin, so it's designed to work with other stuff. And it has an init method that does some stuff. So to test that in our test server val mixin, which is not in the database, so we can use simple test case to make things a bit faster. So we create a dummy field that inherits from the class that's under test plus char field. That class doesn't need to do anything else, so that's why we've got pass there. And when we create this field we're going to be calling the init method. But we don't want to call the init method of char field because I don't care what goes on inside that. I'm not testing Django. I'm testing my code. So I don't want to, I just, I need to patch that thing. And so wherever the top, the wherever server val mixin is defined, that's the thing I put next to patch object, module where it's imported to, not where it's defined, where it's imported to. The init method, auto spec equals true. And it doesn't return anything, so it doesn't return anything. So then in the test I create the test field. You can see I'm using keyword args, the double star, I'm passing in whatever. It doesn't matter what I'm just passing in some dictionary. But this init method is supposed to pass that on. This test case is testing where I provide no settings to the actual mixin. But the mixin is used in the context of where it's mixed in with something else. You never use it alone. And so one of the assertions, which is the bottom one, test to see whether the init method of the, of the base class was called with that 11 and 12 dictionary. That's what that bottom line is doing. So I'm actually seeing, I'm testing the super call in the init method. And if it doesn't pass it on, then my assertion will fail. So just a few comments about mocks. By default, when you create a mock, everything's defined. So if you're testing that it's not there, you need to delete it. Which is under, so in this, this test case here, we see online three and four, the del mock one dot save and del two mock. So this is testing something that is a mixin that could be used with a model form, but it could be used in an ordinary form. And model forms have got a save method and ordinary forms don't. Well, what happens if I want to test it with something that has it and something that doesn't? And is it going to work or is it going to throw an exception? And so this, this test method tests for that. It's setting up a view that's got some forms. It creates a dictionary of forms for one and form two. And it then passes that to the form valid method of the thing that's under test. Another note is at the top you see there's three patches. It's patching the get success URL because that's what form val, if you, when you call form valid, call form valid calls the get success URL. So but I don't want it to do that. I don't want it to go through the class based view hierarchy. I just want it to do what I need this thing to do. I don't want it to redirect. I don't, it's calling the, it's doing, it's saving several forms. It's doing it a transaction. Is that transaction actually in vote? And the assertion that tests for that is the port up from the bottom. One little quick tip when it comes to these patches, when there's more than one of them, the order, you need, it's like a mirror image. The closest one in is the first, the TA patch. Then the next one up is the HR patch. You need to do them in a mirror order. Not the top patches, the first position or argument after self. You do them like in a mirror image is the best way that I've found to think about that. So we're getting low on time. So just a quick, a quick look at template unit testing. So here's a dictionary object that the base test just does what Django does, but it also does indirect lookups. So I tested to see whether it can do those things or not. So all I need to do is to set up a template with a minimal string that just load the test tags and then actually invokes the tag, set up a context, run it, which is what that render function does, dumps the result in rendered, and then I can assert that that rendered, the tag is doing what it's supposed to be doing. All right. So in summary, a unit test is focused on a specific method and that's it. Whatever that method's doing directly or what it's calling. When I say what it's calling, only how it calls it and what comes back. Not what's going on inside. That's effectively a black box. New classes, you set up the instance with sort of a dummy function and you'll probably find versions of that around on the net or I'll look to try and put these slides up. They've got the Twitter handle there so I've got to get them hosted somewhere. So you're testing on arguments to test the cohesion and you use dummy classes, subclasses to test mixing. Mox, they have attributes which we didn't get too much time to go into and you need to delete attributes and methods where you need to test for their absence. So we've got any questions? Do you find that getting in, particularly the last example where you're sort of mocking things and getting into a little bit of the semantics of how the underlying layers work, do you find that tests, the semantics change between versions of Django or versions of Python. In other words, your tests are very detailed and very specific and do you find that there is an additional maintenance burden by getting into that much detail that you're doing? I mean, the tests look very nice but I worry about maintenance. Look, it does exist but it's minimal. And the advantage of testing this way is that it pays off for it so many times. What typically happens as you write all these unit tests is there's a lot of assurance on the underlying code. When you come to do an integration test, you might find that a few bits don't quite fit in quite right but once you fix the cohesion issues, everything just seems to work. Going from one version to Django to the other, the problems that can arise from that where you actually got to change the code under test, not the testing code. Because the testing code is mocking out all this other stuff, but your code is expecting Django to work in a certain way and that's all your testing. So the problems are really when they do arise with your tested code, not your testing code and you want your tests to fail in that situation. So I have a question about how do you go about deciding if an integration test would be better for a particular view rather than, you know, doing a unit test for each little block of code because it seems like with an integration test, you can easily request, do the request and make sure you get back what you're wanting but with a unit test in your examples anyway, there's a lot of setup in terms of mocking the things that you don't want and you have to decide what you don't want and that type of thing. Well, the answer to that is I do both. I integration test the user stories including the alternative cases from use case text. So I want to see that those stories are captured in the integration tests and then the unit test focus on the detail of each function. So I don't do a trade off there. I actually do both and it improves the integrity of the code. Once you get used to these mocks and dummy objects, you get used to pumping them out pretty quickly like the IRM, you can have complicated queries. You don't need to worry about setting up fixtures. You just look at your parameters. An integration test needs fixtures and the integration test will see if your query makes sense or not and then your unit test can deal with all the little edge cases where it will be pretty much impossible to create all those fixtures. So in the end, it ends up working quite quickly. Thank you again, Wayne.
 Thank you for coming.  Can you all hear me?  I don't know if I'll back here.  So today we're going to look at practical unit testing in Django.  If you went to the testing talk yesterday, we're going to dive into it in more detail,  specifically about unit testing rather than general Django testing.  So if you've not done mocking before, a good intro talk is from DjangoCon US 2015, while  unit testing doesn't have to be so hard.  That's when my introduction to mocking happened then, and then using that in a Django context  and a few tears later, then we've sort of developed some techniques.  So that's definitely a good talk to check out if you're new to this area.  And so what we're covering is we're covering unit testing.  We're going to look at some examples of testing with views, forms, fields, and some template  tags.  We're not covering integration testing, so I'm not going to get into whether you should  use or not use mocks when it comes to those things that much, apart from stating a personal  opinion.  I never use mocks in integration tests.  I can avoid it anyway, but they're essential when it comes to unit tests.  So why unit tests?  I started by Django Adventure by doing the tutorial.  And the tutorial has a section on testing.  That section on testing is integration testing.  Now the problem is as a project grows in scope, it becomes very hard to get a high level  of code coverage using the Django test client, where the code that you're trying to test  might be 20 method calls down the tree.  And so that doesn't really work in terms of really exploring the code that you're  placing under test in a particular module.  So we need a more direct way of attacking what we're trying to test rather than trying  to test the whole stack.  In a project, you would do integration testing.  So those tests are still there.  But then you...  So there's a percentage of tests that are integration and functional tests, but a whole  lot of tests are going to be unit tests.  There's many dependencies that can exist in a project.  This can often be more than just take what the parameters that come in and a result that  comes out.  There's side effects.  There's classes.  There's attributes of classes.  You might be changing those attributes of classes.  And so those things are side effects and they increase the complexity of testing.  And so we need a way of getting some sanity about all this because that kind of drives  you crazy.  And sometimes really it can be so complicated it can just not be even plausible to try and  manage it at such a high level.  So what is a unit test?  The idea is to place one method under test.  And you're testing the internal operation of that method.  You're testing how it calls other methods.  And you're looking at what it does when it gets the results of other methods back and  what it might do with that, which might be simply just returning it onwards.  Then you presume everything else is reliable.  So Python's duck place typing.  So can you tell me a bit of interaction here?  What is that animal that we see on the screen?  Oh, we don't see anything on the screen at all now.  Hopefully that stays there.  I'm not going to touch anything.  So the point is it doesn't really matter what is the big picture of what you're testing.  You are testing a method.  So we've got the nose of a duck, a little toy duck on this line.  It doesn't matter the thing is a line.  You're just testing that narrow bit with a nose, that red nose.  And so long as that does, you only need to do enough to make it work in the context of  your method.  Everything else that it does doesn't really matter.  And I'll fill that out in some details as we go along.  But to get you thinking, if you're testing some code that takes an OOM result and you're  say adding something to it, you actually don't need the OOM to test what you are doing.  The OOM itself is out of scope of your particular method.  And we'll have a look at some examples.  The point is if you're testing just at that red nose, that's all that matters.  Everything else is irrelevant.  So our first domain that we want to talk about is testing class-based views.  If you're using functional views, I don't really use them anymore.  So I'm going to be focused on class-based views.  Now, class-based views, there's a big hierarchy and there's lots of methods in there.  What then typically happens is you might be inheriting from, say, Create View or Update  View and you might be defining a few methods that add to that.  Just do a few things extra, maybe just one line of code extra.  What you're testing is that one line of code and the call to the super function and the  result that comes back.  And that's all you're testing.  You're not testing anything else.  So what we...  So as the slide talks about, each override that you make is going to be a method that  you...that you're either deriving from the class and writing a specific override or perhaps  you've noticed you've done that a few times and so now it's time for a mix-in.  And so we're going to define a mix-in that does one or two things in one or two methods  and we want to test that.  So what we want to do is we want to test those methods.  Now what we don't want to do is we don't want to call the Django test client because  that's an integration test and that relies on the whole Kicking a Boot or to be there  and we don't really want that.  So what we need to do is we need to basically create enough of our view in memory so we  can call the function we actually want to test.  And so the top function there is a function that just rips out a little bit of from the  as view function that's from the Django class-based view hierarchy to set up a test object, a  view object, I should say.  So it sets up the attributes for request args and key words and returns the view.  If you look at as view in the Django source code you'll notice that that exists in there.  It does a few other things but they're not really needed for our unit test.  And then to actually test this thing in the setup function in the test class we see that  we go to the request factory.  That was the existence of the request factory as talked about yesterday.  In this case we're testing a get method but that could be other HTTP methods.  It doesn't really matter what URL you give it.  You don't need to worry about URL resolving.  You can call it ABC.  It's really irrelevant.  Just feed it some string.  We create our view which is the view under test and we call that method that's up the  top.  And that sets up the view and then what we can do is we can directly call the method.  If our class under test has got say a dispatch method override then we can just directly  call that by going view.dispatch with the request and any arguments, keyword arguments.  So we can directly call that method and we don't need to worry about everything else  that goes with it.  If we're common functions to override is get context data.  You just call it directly with a dictionary as your keyword args and then you look at what  it does inside.  So moving on to forms.  So we want to test the idea is to test every action of a method to get some kind of assurance  that this code is going to do what it does.  So here's a function we want to test.  It's the clean method of a form and what it does is it's testing two dates and if the  end date is after the start date we just want to make it the same as we want to make the  start date the same as the end date.  So if the start dates later.  So it doesn't do that or not.  And if there's an exception then we want that not, we want it to basically do nothing.  So here are two tests that do that.  So we haven't looked at what they do.  The first thing is they patch the clean method that's inherited.  The super call is going to call the form clean method.  We actually don't want to call the form clean method because we're not interested in testing  what that does.  We just want, so we need to patch that.  And so your suspect means it'll test whether we're calling it in the way that it will be  expected and then we give it a result value.  We're just going to give it a result of ABC.  We call it whatever we want.  And then so then the method, the first line is it creates the form.  Form equals self test form.  Then it sets up some clean data.  Now when you're doing an integration test that's already done somewhere else but we're  just going to be calling clean.  So clean data doesn't exist.  So we need to make that.  That's a dependency.  So we need to set that up and we'll put some clean data in there.  The first one there is no end date so that would throw an exception.  We're testing for only a start date.  Then it says result equals form clean.  It calls the clean method directly.  Then it looks at what comes out.  The first assertion is did it call the super method?  Did that clean method of the form get called?  And was it called once?  Which is what we expect.  The previous method has got one called a super.  What happens if we made a coding error and we called it twice?  Well then the assertion will fail.  Then the next line is it asserts that clean data has only got a start date in it.  There's no end date that appeared because our code is not supposed to do that.  Now if I wanted to pass it, if I wanted to throw the exception and not capture it, I  could use an assertion called assert raises and put the exception in there.  Then the test will pass if an exception is thrown that's not captured.  So I can, whether I need to throw the exception or not, I can test specifically for that.  Then the final thing is this last assertion is the result ABC.  We go back and have a look at the code.  The result from super is put into a variable called result and then down the bottom return  result.  If I leave that bottom line out to get to return the result, then that final assertion  will fail.  So I am testing, it's my method that takes the result of the super call and will pass  that out to the caller.  I want to test that.  That's something that my method is doing.  So anything that my method is doing, I want to test that.  And that's what that final assertion, the set result ABC needs to test.  If I change the return value back on the patch at the top line to D E F, then my assertion  will fail unless I test for D E F.  So that's the concept of detailed unit testing.  So going on, let's just talking about this at a more conceptual level.  So methods do things.  And we want to try and capture each thing that it does.  So some of it is direct in method actions such as assignments or doing some sort of  mathematics or whatever.  And the other thing that they typically do is call stuff.  And most often, but not always, that's a call to super.  But sometimes it's a call to other things.  Whatever it calls, you want to test that it's calling it as you expect it will call it,  given the inputs that you're feeding to this function.  If you say if you only sometimes call super based on certain inputs, then you'll want  test case that test for the domain of inputs that should call super.  And then for the ones that shouldn't call super, you'll be looking that it's call count  is zero.  Now as soon as you introduce an if statement, you've got a code branch.  And so that's likely to mean more than one test case.  So you can test each branch.  If you're getting too many of them and you're getting a whole pile of test cases, that's  a prime indication that you need to break the thing up.  Just a few notes on in the Python mock library has this thing called call args and call args  lists.  So to save you a bit of blood, sweat and tears, the first index element contains all the positional  arguments.  It's not just stuff that you put in star args, but anything that's called as a positional  argument.  The second index is anything that you call as a keyword args.  If the thing is a method that's on an object, self will be the first positional argument.  But if it is a class method, class is not passed as a positional argument, even though  you put it in the code, because Python already knows the name of the class.  So class is actually not passed as the first positional keyword, so first positional arg,  you know you actually physically write CLS or whatever you want to call it in the code.  And if it's a static method where you're expecting nothing to be passed at that stage, call args  list is used when you're calling the function more than once.  It allows you to make assertions on the parameters for each call.  So next thing is mixins.  So we discussed the mixins a little bit before.  So if you write a mixin and you be wanting to test its method, so in this case we've  got a validation object which is designed, it's a mixin, so it's designed to work with  other stuff.  And it has an init method that does some stuff.  So to test that in our test server val mixin, which is not in the database, so we can use  simple test case to make things a bit faster.  So we create a dummy field that inherits from the class that's under test plus char field.  That class doesn't need to do anything else, so that's why we've got pass there.  And when we create this field we're going to be calling the init method.  But we don't want to call the init method of char field because I don't care what goes  on inside that.  I'm not testing Django.  I'm testing my code.  So I don't want to, I just, I need to patch that thing.  And so wherever the top, the wherever server val mixin is defined, that's the thing I put  next to patch object, module where it's imported to, not where it's defined, where it's imported  to.  The init method, auto spec equals true.  And it doesn't return anything, so it doesn't return anything.  So then in the test I create the test field.  You can see I'm using keyword args, the double star, I'm passing in whatever.  It doesn't matter what I'm just passing in some dictionary.  But this init method is supposed to pass that on.  This test case is testing where I provide no settings to the actual mixin.  But the mixin is used in the context of where it's mixed in with something else.  You never use it alone.  And so one of the assertions, which is the bottom one, test to see whether the init  method of the, of the base class was called with that 11 and 12 dictionary.  That's what that bottom line is doing.  So I'm actually seeing, I'm testing the super call in the init method.  And if it doesn't pass it on, then my assertion will fail.  So just a few comments about mocks.  By default, when you create a mock, everything's defined.  So if you're testing that it's not there, you need to delete it.  Which is under, so in this, this test case here, we see online three and four, the del  mock one dot save and del two mock.  So this is testing something that is a mixin that could be used with a model form, but  it could be used in an ordinary form.  And model forms have got a save method and ordinary forms don't.  Well, what happens if I want to test it with something that has it and something that doesn't?  And is it going to work or is it going to throw an exception?  And so this, this test method tests for that.  It's setting up a view that's got some forms.  It creates a dictionary of forms for one and form two.  And it then passes that to the form valid method of the thing that's under test.  Another note is at the top you see there's three patches.  It's patching the get success URL because that's what form val, if you, when you call  form valid, call form valid calls the get success URL.  So but I don't want it to do that.  I don't want it to go through the class based view hierarchy.  I just want it to do what I need this thing to do.  I don't want it to redirect.  I don't, it's calling the, it's doing, it's saving several forms.  It's doing it a transaction.  Is that transaction actually in vote?  And the assertion that tests for that is the port up from the bottom.  One little quick tip when it comes to these patches, when there's more than one of them,  the order, you need, it's like a mirror image.  The closest one in is the first, the TA patch.  Then the next one up is the HR patch.  You need to do them in a mirror order.  Not the top patches, the first position or argument after self.  You do them like in a mirror image is the best way that I've found to think about that.  So we're getting low on time.  So just a quick, a quick look at template unit testing.  So here's a dictionary object that the base test just does what Django does, but it also  does indirect lookups.  So I tested to see whether it can do those things or not.  So all I need to do is to set up a template with a minimal string that just load the test  tags and then actually invokes the tag, set up a context, run it, which is what that render  function does, dumps the result in rendered, and then I can assert that that rendered,  the tag is doing what it's supposed to be doing.  All right.  So in summary, a unit test is focused on a specific method and that's it.  Whatever that method's doing directly or what it's calling.  When I say what it's calling, only how it calls it and what comes back.  Not what's going on inside.  That's effectively a black box.  New classes, you set up the instance with sort of a dummy function and you'll probably  find versions of that around on the net or I'll look to try and put these slides up.  They've got the Twitter handle there so I've got to get them hosted somewhere.  So you're testing on arguments to test the cohesion and you use dummy classes, subclasses  to test mixing.  Mox, they have attributes which we didn't get too much time to go into and you need  to delete attributes and methods where you need to test for their absence.  So we've got any questions?  Do you find that getting in, particularly the last example where you're sort of mocking  things and getting into a little bit of the semantics of how the underlying layers work,  do you find that tests, the semantics change between versions of Django or versions of  Python.  In other words, your tests are very detailed and very specific and do you find that there  is an additional maintenance burden by getting into that much detail that you're doing?  I mean, the tests look very nice but I worry about maintenance.  Look, it does exist but it's minimal.  And the advantage of testing this way is that it pays off for it so many times.  What typically happens as you write all these unit tests is there's a lot of assurance on  the underlying code.  When you come to do an integration test, you might find that a few bits don't quite fit  in quite right but once you fix the cohesion issues, everything just seems to work.  Going from one version to Django to the other, the problems that can arise from that where  you actually got to change the code under test, not the testing code.  Because the testing code is mocking out all this other stuff, but your code is expecting  Django to work in a certain way and that's all your testing.  So the problems are really when they do arise with your tested code, not your testing code  and you want your tests to fail in that situation.  So I have a question about how do you go about deciding if an integration test would be better  for a particular view rather than, you know, doing a unit test for each little block of  code because it seems like with an integration test, you can easily request, do the request  and make sure you get back what you're wanting but with a unit test in your examples anyway,  there's a lot of setup in terms of mocking the things that you don't want and you have  to decide what you don't want and that type of thing.  Well, the answer to that is I do both.  I integration test the user stories including the alternative cases from use case text.  So I want to see that those stories are captured in the integration tests and then the unit  test focus on the detail of each function.  So I don't do a trade off there.  I actually do both and it improves the integrity of the code.  Once you get used to these mocks and dummy objects, you get used to pumping them out  pretty quickly like the IRM, you can have complicated queries.  You don't need to worry about setting up fixtures.  You just look at your parameters.  An integration test needs fixtures and the integration test will see if your query makes  sense or not and then your unit test can deal with all the little edge cases where it will  be pretty much impossible to create all those fixtures.  So in the end, it ends up working quite quickly.  Thank you again, Wayne.
Practical_Unit_Testing_in_Django_0_131.png Practical_Unit_Testing_in_Django_132_251.png Practical_Unit_Testing_in_Django_252_359.png Practical_Unit_Testing_in_Django_360_731.png Practical_Unit_Testing_in_Django_732_887.png Practical_Unit_Testing_in_Django_888_1667.png Practical_Unit_Testing_in_Django_1668_2363.png Practical_Unit_Testing_in_Django_2364_5735.png Practical_Unit_Testing_in_Django_5736_7655.png Practical_Unit_Testing_in_Django_7656_9467.png Practical_Unit_Testing_in_Django_9468_12491.png Practical_Unit_Testing_in_Django_12492_13499.png Practical_Unit_Testing_in_Django_13500_15791.png Practical_Unit_Testing_in_Django_15792_18047.png Practical_Unit_Testing_in_Django_18048_19835.png Practical_Unit_Testing_in_Django_19836_21587.png Practical_Unit_Testing_in_Django_21588_31055.png Practical_Unit_Testing_in_Django_31056_31103.png Practical_Unit_Testing_in_Django_31104_31247.png Practical_Unit_Testing_in_Django_31248_31355.png Practical_Unit_Testing_in_Django_31356_31475.png Practical_Unit_Testing_in_Django_31476_31883.png Practical_Unit_Testing_in_Django_31884_31955.png Practical_Unit_Testing_in_Django_31956_32003.png Practical_Unit_Testing_in_Django_32004_32303.png Practical_Unit_Testing_in_Django_32304_33107.png Practical_Unit_Testing_in_Django_33108_33299.png Practical_Unit_Testing_in_Django_33300_33347.png Practical_Unit_Testing_in_Django_33348_35639.png Practical_Unit_Testing_in_Django_35640_35711.png Practical_Unit_Testing_in_Django_35712_35759.png Practical_Unit_Testing_in_Django_35760_35855.png Practical_Unit_Testing_in_Django_35856_35899.png
Thank you for coming. Can you all hear me? I don't know if I'll back here. So today we're going to look at practical unit testing in Django. If you went to the testing talk yesterday, we're going to dive into it in more detail, specifically about unit testing rather than general Django testing. So if you've not done mocking before, a good intro talk is from DjangoCon US 2015, while unit testing doesn't have to be so hard. That's when my introduction to mocking happened then, and then using that in a Django context and a few tears later, then we've sort of developed some techniques. So that's definitely a good talk to check out if you're new to this area. And so what we're covering is we're covering unit testing. We're going to look at some examples of testing with views, forms, fields, and some template tags. We're not covering integration testing, so I'm not going to get into whether you should use or not use mocks when it comes to those things that much, apart from stating a personal opinion. I never use mocks in integration tests. I can avoid it anyway, but they're essential when it comes to unit tests. So why unit tests? I started by Django Adventure by doing the tutorial. And the tutorial has a section on testing. That section on testing is integration testing. Now the problem is as a project grows in scope, it becomes very hard to get a high level of code coverage using the Django test client, where the code that you're trying to test might be 20 method calls down the tree. And so that doesn't really work in terms of really exploring the code that you're placing under test in a particular module. So we need a more direct way of attacking what we're trying to test rather than trying to test the whole stack. In a project, you would do integration testing. So those tests are still there. But then you... So there's a percentage of tests that are integration and functional tests, but a whole lot of tests are going to be unit tests. There's many dependencies that can exist in a project. This can often be more than just take what the parameters that come in and a result that comes out. There's side effects. There's classes. There's attributes of classes. You might be changing those attributes of classes. And so those things are side effects and they increase the complexity of testing. And so we need a way of getting some sanity about all this because that kind of drives you crazy. And sometimes really it can be so complicated it can just not be even plausible to try and manage it at such a high level. So what is a unit test? The idea is to place one method under test. And you're testing the internal operation of that method. You're testing how it calls other methods. And you're looking at what it does when it gets the results of other methods back and what it might do with that, which might be simply just returning it onwards. Then you presume everything else is reliable. So Python's duck place typing. So can you tell me a bit of interaction here? What is that animal that we see on the screen? Oh, we don't see anything on the screen at all now. Hopefully that stays there. I'm not going to touch anything. So the point is it doesn't really matter what is the big picture of what you're testing. You are testing a method. So we've got the nose of a duck, a little toy duck on this line. It doesn't matter the thing is a line. You're just testing that narrow bit with a nose, that red nose. And so long as that does, you only need to do enough to make it work in the context of your method. Everything else that it does doesn't really matter. And I'll fill that out in some details as we go along. But to get you thinking, if you're testing some code that takes an OOM result and you're say adding something to it, you actually don't need the OOM to test what you are doing. The OOM itself is out of scope of your particular method. And we'll have a look at some examples. The point is if you're testing just at that red nose, that's all that matters. Everything else is irrelevant. So our first domain that we want to talk about is testing class-based views. If you're using functional views, I don't really use them anymore. So I'm going to be focused on class-based views. Now, class-based views, there's a big hierarchy and there's lots of methods in there. What then typically happens is you might be inheriting from, say, Create View or Update View and you might be defining a few methods that add to that. Just do a few things extra, maybe just one line of code extra. What you're testing is that one line of code and the call to the super function and the result that comes back. And that's all you're testing. You're not testing anything else. So what we... So as the slide talks about, each override that you make is going to be a method that you...that you're either deriving from the class and writing a specific override or perhaps you've noticed you've done that a few times and so now it's time for a mix-in. And so we're going to define a mix-in that does one or two things in one or two methods and we want to test that. So what we want to do is we want to test those methods. Now what we don't want to do is we don't want to call the Django test client because that's an integration test and that relies on the whole Kicking a Boot or to be there and we don't really want that. So what we need to do is we need to basically create enough of our view in memory so we can call the function we actually want to test. And so the top function there is a function that just rips out a little bit of from the as view function that's from the Django class-based view hierarchy to set up a test object, a view object, I should say. So it sets up the attributes for request args and key words and returns the view. If you look at as view in the Django source code you'll notice that that exists in there. It does a few other things but they're not really needed for our unit test. And then to actually test this thing in the setup function in the test class we see that we go to the request factory. That was the existence of the request factory as talked about yesterday. In this case we're testing a get method but that could be other HTTP methods. It doesn't really matter what URL you give it. You don't need to worry about URL resolving. You can call it ABC. It's really irrelevant. Just feed it some string. We create our view which is the view under test and we call that method that's up the top. And that sets up the view and then what we can do is we can directly call the method. If our class under test has got say a dispatch method override then we can just directly call that by going view.dispatch with the request and any arguments, keyword arguments. So we can directly call that method and we don't need to worry about everything else that goes with it. If we're common functions to override is get context data. You just call it directly with a dictionary as your keyword args and then you look at what it does inside. So moving on to forms. So we want to test the idea is to test every action of a method to get some kind of assurance that this code is going to do what it does. So here's a function we want to test. It's the clean method of a form and what it does is it's testing two dates and if the end date is after the start date we just want to make it the same as we want to make the start date the same as the end date. So if the start dates later. So it doesn't do that or not. And if there's an exception then we want that not, we want it to basically do nothing. So here are two tests that do that. So we haven't looked at what they do. The first thing is they patch the clean method that's inherited. The super call is going to call the form clean method. We actually don't want to call the form clean method because we're not interested in testing what that does. We just want, so we need to patch that. And so your suspect means it'll test whether we're calling it in the way that it will be expected and then we give it a result value. We're just going to give it a result of ABC. We call it whatever we want. And then so then the method, the first line is it creates the form. Form equals self test form. Then it sets up some clean data. Now when you're doing an integration test that's already done somewhere else but we're just going to be calling clean. So clean data doesn't exist. So we need to make that. That's a dependency. So we need to set that up and we'll put some clean data in there. The first one there is no end date so that would throw an exception. We're testing for only a start date. Then it says result equals form clean. It calls the clean method directly. Then it looks at what comes out. The first assertion is did it call the super method? Did that clean method of the form get called? And was it called once? Which is what we expect. The previous method has got one called a super. What happens if we made a coding error and we called it twice? Well then the assertion will fail. Then the next line is it asserts that clean data has only got a start date in it. There's no end date that appeared because our code is not supposed to do that. Now if I wanted to pass it, if I wanted to throw the exception and not capture it, I could use an assertion called assert raises and put the exception in there. Then the test will pass if an exception is thrown that's not captured. So I can, whether I need to throw the exception or not, I can test specifically for that. Then the final thing is this last assertion is the result ABC. We go back and have a look at the code. The result from super is put into a variable called result and then down the bottom return result. If I leave that bottom line out to get to return the result, then that final assertion will fail. So I am testing, it's my method that takes the result of the super call and will pass that out to the caller. I want to test that. That's something that my method is doing. So anything that my method is doing, I want to test that. And that's what that final assertion, the set result ABC needs to test. If I change the return value back on the patch at the top line to D E F, then my assertion will fail unless I test for D E F. So that's the concept of detailed unit testing. So going on, let's just talking about this at a more conceptual level. So methods do things. And we want to try and capture each thing that it does. So some of it is direct in method actions such as assignments or doing some sort of mathematics or whatever. And the other thing that they typically do is call stuff. And most often, but not always, that's a call to super. But sometimes it's a call to other things. Whatever it calls, you want to test that it's calling it as you expect it will call it, given the inputs that you're feeding to this function. If you say if you only sometimes call super based on certain inputs, then you'll want test case that test for the domain of inputs that should call super. And then for the ones that shouldn't call super, you'll be looking that it's call count is zero. Now as soon as you introduce an if statement, you've got a code branch. And so that's likely to mean more than one test case. So you can test each branch. If you're getting too many of them and you're getting a whole pile of test cases, that's a prime indication that you need to break the thing up. Just a few notes on in the Python mock library has this thing called call args and call args lists. So to save you a bit of blood, sweat and tears, the first index element contains all the positional arguments. It's not just stuff that you put in star args, but anything that's called as a positional argument. The second index is anything that you call as a keyword args. If the thing is a method that's on an object, self will be the first positional argument. But if it is a class method, class is not passed as a positional argument, even though you put it in the code, because Python already knows the name of the class. So class is actually not passed as the first positional keyword, so first positional arg, you know you actually physically write CLS or whatever you want to call it in the code. And if it's a static method where you're expecting nothing to be passed at that stage, call args list is used when you're calling the function more than once. It allows you to make assertions on the parameters for each call. So next thing is mixins. So we discussed the mixins a little bit before. So if you write a mixin and you be wanting to test its method, so in this case we've got a validation object which is designed, it's a mixin, so it's designed to work with other stuff. And it has an init method that does some stuff. So to test that in our test server val mixin, which is not in the database, so we can use simple test case to make things a bit faster. So we create a dummy field that inherits from the class that's under test plus char field. That class doesn't need to do anything else, so that's why we've got pass there. And when we create this field we're going to be calling the init method. But we don't want to call the init method of char field because I don't care what goes on inside that. I'm not testing Django. I'm testing my code. So I don't want to, I just, I need to patch that thing. And so wherever the top, the wherever server val mixin is defined, that's the thing I put next to patch object, module where it's imported to, not where it's defined, where it's imported to. The init method, auto spec equals true. And it doesn't return anything, so it doesn't return anything. So then in the test I create the test field. You can see I'm using keyword args, the double star, I'm passing in whatever. It doesn't matter what I'm just passing in some dictionary. But this init method is supposed to pass that on. This test case is testing where I provide no settings to the actual mixin. But the mixin is used in the context of where it's mixed in with something else. You never use it alone. And so one of the assertions, which is the bottom one, test to see whether the init method of the, of the base class was called with that 11 and 12 dictionary. That's what that bottom line is doing. So I'm actually seeing, I'm testing the super call in the init method. And if it doesn't pass it on, then my assertion will fail. So just a few comments about mocks. By default, when you create a mock, everything's defined. So if you're testing that it's not there, you need to delete it. Which is under, so in this, this test case here, we see online three and four, the del mock one dot save and del two mock. So this is testing something that is a mixin that could be used with a model form, but it could be used in an ordinary form. And model forms have got a save method and ordinary forms don't. Well, what happens if I want to test it with something that has it and something that doesn't? And is it going to work or is it going to throw an exception? And so this, this test method tests for that. It's setting up a view that's got some forms. It creates a dictionary of forms for one and form two. And it then passes that to the form valid method of the thing that's under test. Another note is at the top you see there's three patches. It's patching the get success URL because that's what form val, if you, when you call form valid, call form valid calls the get success URL. So but I don't want it to do that. I don't want it to go through the class based view hierarchy. I just want it to do what I need this thing to do. I don't want it to redirect. I don't, it's calling the, it's doing, it's saving several forms. It's doing it a transaction. Is that transaction actually in vote? And the assertion that tests for that is the port up from the bottom. One little quick tip when it comes to these patches, when there's more than one of them, the order, you need, it's like a mirror image. The closest one in is the first, the TA patch. Then the next one up is the HR patch. You need to do them in a mirror order. Not the top patches, the first position or argument after self. You do them like in a mirror image is the best way that I've found to think about that. So we're getting low on time. So just a quick, a quick look at template unit testing. So here's a dictionary object that the base test just does what Django does, but it also does indirect lookups. So I tested to see whether it can do those things or not. So all I need to do is to set up a template with a minimal string that just load the test tags and then actually invokes the tag, set up a context, run it, which is what that render function does, dumps the result in rendered, and then I can assert that that rendered, the tag is doing what it's supposed to be doing. All right. So in summary, a unit test is focused on a specific method and that's it. Whatever that method's doing directly or what it's calling. When I say what it's calling, only how it calls it and what comes back. Not what's going on inside. That's effectively a black box. New classes, you set up the instance with sort of a dummy function and you'll probably find versions of that around on the net or I'll look to try and put these slides up. They've got the Twitter handle there so I've got to get them hosted somewhere. So you're testing on arguments to test the cohesion and you use dummy classes, subclasses to test mixing. Mox, they have attributes which we didn't get too much time to go into and you need to delete attributes and methods where you need to test for their absence. So we've got any questions? Do you find that getting in, particularly the last example where you're sort of mocking things and getting into a little bit of the semantics of how the underlying layers work, do you find that tests, the semantics change between versions of Django or versions of Python. In other words, your tests are very detailed and very specific and do you find that there is an additional maintenance burden by getting into that much detail that you're doing? I mean, the tests look very nice but I worry about maintenance. Look, it does exist but it's minimal. And the advantage of testing this way is that it pays off for it so many times. What typically happens as you write all these unit tests is there's a lot of assurance on the underlying code. When you come to do an integration test, you might find that a few bits don't quite fit in quite right but once you fix the cohesion issues, everything just seems to work. Going from one version to Django to the other, the problems that can arise from that where you actually got to change the code under test, not the testing code. Because the testing code is mocking out all this other stuff, but your code is expecting Django to work in a certain way and that's all your testing. So the problems are really when they do arise with your tested code, not your testing code and you want your tests to fail in that situation. So I have a question about how do you go about deciding if an integration test would be better for a particular view rather than, you know, doing a unit test for each little block of code because it seems like with an integration test, you can easily request, do the request and make sure you get back what you're wanting but with a unit test in your examples anyway, there's a lot of setup in terms of mocking the things that you don't want and you have to decide what you don't want and that type of thing. Well, the answer to that is I do both. I integration test the user stories including the alternative cases from use case text. So I want to see that those stories are captured in the integration tests and then the unit test focus on the detail of each function. So I don't do a trade off there. I actually do both and it improves the integrity of the code. Once you get used to these mocks and dummy objects, you get used to pumping them out pretty quickly like the IRM, you can have complicated queries. You don't need to worry about setting up fixtures. You just look at your parameters. An integration test needs fixtures and the integration test will see if your query makes sense or not and then your unit test can deal with all the little edge cases where it will be pretty much impossible to create all those fixtures. So in the end, it ends up working quite quickly. Thank you again, Wayne.
going to look at practical unit testing in going to look at some examples of testing with views, forms, fields, and some template tags. unit tests. So why unit tests? I started by on testing is integration testing. Now the coverage using the Django test client, where the test the whole stack. In a project, you would do tests that are integration and functional tests, in a project. This can often be more than just take what the parameters that come in and a they increase the complexity of testing. And so at such a high level. So what is a unit test? The idea is to place one method under test. And of what you're testing. You are testing a method. you only need to do enough to make it work in the our first domain that we want to talk about is you might be inheriting from, say, Create View or you're testing is that one line of code and the a specific override or perhaps you've noticed for a mix-in. And so we're going to define a methods and we want to test that. So what we want Django test client because that's an integration up a test object, a view object, I should say. So common functions to override is get context data. test the idea is to test every action of a method clean. It calls the clean method directly. Then use an assertion called assert raises and put the of the super call and will pass that out to the that's the concept of detailed unit testing. So So some of it is direct in method actions such as is a class method, class is not passed as a on the parameters for each call. So next thing is class that's under test plus char field. That in this, this test case here, we see online three mock. So this is testing something that is a method tests for that. It's setting up a view that to the form valid method of the thing that's based view hierarchy. I just want it to do what I than one of them, the order, you need, it's like to test the cohesion and you use dummy classes, methods where you need to test for their absence. getting in, particularly the last example where many times. What typically happens as you write assurance on the underlying code. When you come testing code is mocking out all this other stuff, but your code is expecting Django to work in a tested code, not your testing code and you want you're wanting but with a unit test in your integration tests and then the unit test focus on used to these mocks and dummy objects, you get needs fixtures and the integration test will see unit test can deal with all the little edge cases