Testing a Django model with custom save method calling external API
up vote
0
down vote
favorite
i'm pretty new to unittests and want to make some "simple" beginner tests in my Django application, I have a model with a "custom" save method that calls a external api if new. Can't figure out how to that that model without calling the external API, how do a implement a mock solution for this?
class Task(models.Model):
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default='new')
....
def _create(self):
....
return requests.post(API_URL + url, json=payload).json()
def save(self, *args, **kwargs):
is_new = self.created is None
super(Task, self).save(*args, **kwargs)
if is_new:
self._create()
class TaskTestCase(TestCase):
def setUp(self):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
django django-unittest
add a comment |
up vote
0
down vote
favorite
i'm pretty new to unittests and want to make some "simple" beginner tests in my Django application, I have a model with a "custom" save method that calls a external api if new. Can't figure out how to that that model without calling the external API, how do a implement a mock solution for this?
class Task(models.Model):
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default='new')
....
def _create(self):
....
return requests.post(API_URL + url, json=payload).json()
def save(self, *args, **kwargs):
is_new = self.created is None
super(Task, self).save(*args, **kwargs)
if is_new:
self._create()
class TaskTestCase(TestCase):
def setUp(self):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
django django-unittest
You can look into this: realpython.com/testing-third-party-apis-with-mocks
– ruddra
Nov 7 at 10:28
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
i'm pretty new to unittests and want to make some "simple" beginner tests in my Django application, I have a model with a "custom" save method that calls a external api if new. Can't figure out how to that that model without calling the external API, how do a implement a mock solution for this?
class Task(models.Model):
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default='new')
....
def _create(self):
....
return requests.post(API_URL + url, json=payload).json()
def save(self, *args, **kwargs):
is_new = self.created is None
super(Task, self).save(*args, **kwargs)
if is_new:
self._create()
class TaskTestCase(TestCase):
def setUp(self):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
django django-unittest
i'm pretty new to unittests and want to make some "simple" beginner tests in my Django application, I have a model with a "custom" save method that calls a external api if new. Can't figure out how to that that model without calling the external API, how do a implement a mock solution for this?
class Task(models.Model):
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default='new')
....
def _create(self):
....
return requests.post(API_URL + url, json=payload).json()
def save(self, *args, **kwargs):
is_new = self.created is None
super(Task, self).save(*args, **kwargs)
if is_new:
self._create()
class TaskTestCase(TestCase):
def setUp(self):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
django django-unittest
django django-unittest
asked Nov 7 at 10:25
pkdkk
1,68973055
1,68973055
You can look into this: realpython.com/testing-third-party-apis-with-mocks
– ruddra
Nov 7 at 10:28
add a comment |
You can look into this: realpython.com/testing-third-party-apis-with-mocks
– ruddra
Nov 7 at 10:28
You can look into this: realpython.com/testing-third-party-apis-with-mocks
– ruddra
Nov 7 at 10:28
You can look into this: realpython.com/testing-third-party-apis-with-mocks
– ruddra
Nov 7 at 10:28
add a comment |
1 Answer
1
active
oldest
votes
up vote
3
down vote
This is a typical use case for python mock library. In your case I will probably looks like this
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
You can use mock.patch as a decorator but also as a context manager if you want to mock a function call on a specific part of your code. See the documentation for more details.
More details
In this example we only mocked the method to avoid the called being really made. In some cases in can be a good idea to also checked that the mocked method was called, and with which arguments.
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
# The most basic way to check a call was performed
mocked_post..assert_called()
# Checking the number of call can be a good idea
mocked_post.assert_called_once()
# Same idea but it also checks the arguments of the method.
mocked_post.assert_called_once_with()
The last option is very useful to test that your are sending the right data to the external service. More details on the different options in the documentation.
Why mocking external calls is a good idea
Mocking all the external calls you can in your test suite is really a good idea. Here is a few reasons why:
- It will improve performance and speed of your test suite. Network calls are generally time expensive, lowering the number of calls will speed up your test suite.
- It allows you to test the data you are sending to other services. As seen with assert_called_once_with you can assert that you are sending once the proper data to other services
- It makes your test suite more predictable. Use mocks you won't rely on any other services to test your application. From time to time external services may not respond properly (maintenance, too many requests, etc.). Using mock you will break the coupling between your test suite and other services
- You can run tests offline (commuting, train, place, etc.).
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
1
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either usemocked_post.return_value = {}
or usemocked_post.side_effect
to use a function to return a value
– Anto
Nov 8 at 19:46
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
This is a typical use case for python mock library. In your case I will probably looks like this
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
You can use mock.patch as a decorator but also as a context manager if you want to mock a function call on a specific part of your code. See the documentation for more details.
More details
In this example we only mocked the method to avoid the called being really made. In some cases in can be a good idea to also checked that the mocked method was called, and with which arguments.
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
# The most basic way to check a call was performed
mocked_post..assert_called()
# Checking the number of call can be a good idea
mocked_post.assert_called_once()
# Same idea but it also checks the arguments of the method.
mocked_post.assert_called_once_with()
The last option is very useful to test that your are sending the right data to the external service. More details on the different options in the documentation.
Why mocking external calls is a good idea
Mocking all the external calls you can in your test suite is really a good idea. Here is a few reasons why:
- It will improve performance and speed of your test suite. Network calls are generally time expensive, lowering the number of calls will speed up your test suite.
- It allows you to test the data you are sending to other services. As seen with assert_called_once_with you can assert that you are sending once the proper data to other services
- It makes your test suite more predictable. Use mocks you won't rely on any other services to test your application. From time to time external services may not respond properly (maintenance, too many requests, etc.). Using mock you will break the coupling between your test suite and other services
- You can run tests offline (commuting, train, place, etc.).
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
1
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either usemocked_post.return_value = {}
or usemocked_post.side_effect
to use a function to return a value
– Anto
Nov 8 at 19:46
add a comment |
up vote
3
down vote
This is a typical use case for python mock library. In your case I will probably looks like this
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
You can use mock.patch as a decorator but also as a context manager if you want to mock a function call on a specific part of your code. See the documentation for more details.
More details
In this example we only mocked the method to avoid the called being really made. In some cases in can be a good idea to also checked that the mocked method was called, and with which arguments.
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
# The most basic way to check a call was performed
mocked_post..assert_called()
# Checking the number of call can be a good idea
mocked_post.assert_called_once()
# Same idea but it also checks the arguments of the method.
mocked_post.assert_called_once_with()
The last option is very useful to test that your are sending the right data to the external service. More details on the different options in the documentation.
Why mocking external calls is a good idea
Mocking all the external calls you can in your test suite is really a good idea. Here is a few reasons why:
- It will improve performance and speed of your test suite. Network calls are generally time expensive, lowering the number of calls will speed up your test suite.
- It allows you to test the data you are sending to other services. As seen with assert_called_once_with you can assert that you are sending once the proper data to other services
- It makes your test suite more predictable. Use mocks you won't rely on any other services to test your application. From time to time external services may not respond properly (maintenance, too many requests, etc.). Using mock you will break the coupling between your test suite and other services
- You can run tests offline (commuting, train, place, etc.).
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
1
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either usemocked_post.return_value = {}
or usemocked_post.side_effect
to use a function to return a value
– Anto
Nov 8 at 19:46
add a comment |
up vote
3
down vote
up vote
3
down vote
This is a typical use case for python mock library. In your case I will probably looks like this
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
You can use mock.patch as a decorator but also as a context manager if you want to mock a function call on a specific part of your code. See the documentation for more details.
More details
In this example we only mocked the method to avoid the called being really made. In some cases in can be a good idea to also checked that the mocked method was called, and with which arguments.
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
# The most basic way to check a call was performed
mocked_post..assert_called()
# Checking the number of call can be a good idea
mocked_post.assert_called_once()
# Same idea but it also checks the arguments of the method.
mocked_post.assert_called_once_with()
The last option is very useful to test that your are sending the right data to the external service. More details on the different options in the documentation.
Why mocking external calls is a good idea
Mocking all the external calls you can in your test suite is really a good idea. Here is a few reasons why:
- It will improve performance and speed of your test suite. Network calls are generally time expensive, lowering the number of calls will speed up your test suite.
- It allows you to test the data you are sending to other services. As seen with assert_called_once_with you can assert that you are sending once the proper data to other services
- It makes your test suite more predictable. Use mocks you won't rely on any other services to test your application. From time to time external services may not respond properly (maintenance, too many requests, etc.). Using mock you will break the coupling between your test suite and other services
- You can run tests offline (commuting, train, place, etc.).
This is a typical use case for python mock library. In your case I will probably looks like this
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
def test_get_new_task(self):
task = Task.objects.all()[0]
self.assertEqual(task.status, 'new')
You can use mock.patch as a decorator but also as a context manager if you want to mock a function call on a specific part of your code. See the documentation for more details.
More details
In this example we only mocked the method to avoid the called being really made. In some cases in can be a good idea to also checked that the mocked method was called, and with which arguments.
import mock
class TaskTestCase(TestCase):
@mock.patch("request.post")
def setUp(self, mocked_post):
self.task = Task.objects.create(status='new')
# The most basic way to check a call was performed
mocked_post..assert_called()
# Checking the number of call can be a good idea
mocked_post.assert_called_once()
# Same idea but it also checks the arguments of the method.
mocked_post.assert_called_once_with()
The last option is very useful to test that your are sending the right data to the external service. More details on the different options in the documentation.
Why mocking external calls is a good idea
Mocking all the external calls you can in your test suite is really a good idea. Here is a few reasons why:
- It will improve performance and speed of your test suite. Network calls are generally time expensive, lowering the number of calls will speed up your test suite.
- It allows you to test the data you are sending to other services. As seen with assert_called_once_with you can assert that you are sending once the proper data to other services
- It makes your test suite more predictable. Use mocks you won't rely on any other services to test your application. From time to time external services may not respond properly (maintenance, too many requests, etc.). Using mock you will break the coupling between your test suite and other services
- You can run tests offline (commuting, train, place, etc.).
answered Nov 7 at 10:42
Anto
862
862
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
1
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either usemocked_post.return_value = {}
or usemocked_post.side_effect
to use a function to return a value
– Anto
Nov 8 at 19:46
add a comment |
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
1
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either usemocked_post.return_value = {}
or usemocked_post.side_effect
to use a function to return a value
– Anto
Nov 8 at 19:46
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
Thanks for the great answer,. One thing, when I try out you example, i get an error due to the requests response.. <MagicMock name='post().json().get()' id='4441346384'> is not JSON serializable .. do you have an idea how to make that work.. can i "use" some example data from the external response?
– pkdkk
Nov 8 at 13:44
1
1
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either use
mocked_post.return_value = {}
or use mocked_post.side_effect
to use a function to return a value– Anto
Nov 8 at 19:46
@pkdkk this is propably due to the fact that the mock you have setup does not return any value. You can either use
mocked_post.return_value = {}
or use mocked_post.side_effect
to use a function to return a value– Anto
Nov 8 at 19:46
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53187580%2ftesting-a-django-model-with-custom-save-method-calling-external-api%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You can look into this: realpython.com/testing-third-party-apis-with-mocks
– ruddra
Nov 7 at 10:28