Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revision: integration testing #63

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 1 addition & 3 deletions _toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
- file: testgranularity/unittesting
sections:
- file: testgranularity/organization_of_unit_tests.ipynb
- file: testgranularity/integrationtesting
sections:
- file: testgranularity/mocking.ipynb
- file: testgranularity/integrationtesting.ipynb
- file: testgranularity/systemtesting
- file: testgranularity/acceptancetesting/acceptancetesting.ipynb

Expand Down
131 changes: 0 additions & 131 deletions testgranularity/driver.ipynb

This file was deleted.

175 changes: 175 additions & 0 deletions testgranularity/integrationtesting.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Integration Testing\n",
"===================\n",
"\n",
"It is a step in the testing process that lies among unit tests and system tests. All the modules of the system, that ideally were tested in unit tests, are combined to guarantee that they work together properly. We can consider that it works as a preparation for System tests. Data is transferred between the modules and is tested thoroughly.\n",
"\n",
"Let's consider a scenario where a mailing system that records all emails sent is developed, and its modules are assigned to different developers. Using the image below as an example, each module could be due to a different programer to develop in order to increase velocity. The front API can be any kind of interface for the client to invoke like a website or a rest API, the controller is responsible for invoking the mailer service and recording the history using the Data Access Layer which is a layer for accessing some kind of storage which will be able to save the emails history in a structure somehow.\n",
"\n",
"![Diagram](../assets/integrationtesting_diagram.png)\n",
"\n",
"## Hands On\n",
"\n",
"- A Driver example with Python\n",
"<a href=\"https://colab.research.google.com/github/damorimRG/practical_testing_book/blob/master/testgranularity/driver.ipynb\" target=\"_blank\"> \n",
" <img alt=\"Open In Colab\" src=\"https://colab.research.google.com/assets/colab-badge.svg\">\n",
"</a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First we implement a common interface which has a contract of how we are going to call the lower modules under construction"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class ControllerInterface():\n",
" def __init__(self, mailer):\n",
" raise NotImplementedError\n",
"\n",
" def call_mailer(self, data):\n",
" raise NotImplementedError"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we need to implement this interface with a dummy object just to pass our current module as its dependency so we are able to test the controller calling for mailer"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"class DummyController(ControllerInterface):\n",
" def __init__(self, mailer):\n",
" self.mailer = mailer\n",
" \n",
" def call_mailer(self, data):\n",
" self.mailer.send(data)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After this we must test if calling the DummyController will invoke the mailer with the correct args and to do so we must define a mailer for now and we are able to use the patch object from the unittest.mock library to check if a function was called correctly"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class Mailer():\n",
" def send(self, data):\n",
" pass"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"from unittest.mock import patch"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are able to check if a function was called with certain arguments by using `assert_called_with`"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"@patch.object(Mailer, 'send')\n",
"def test_controller(mock_send):\n",
" controller = DummyController(Mailer())\n",
" data = {}\n",
" controller.call_mailer(data)\n",
" mock_send.assert_called_with(data)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"test_controller()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Integration Strategies\n",
"\n",
"There are some methods to tackle the issue of testing this whole flow regarding the development of tests, one of them is the *Big Bang* [1] method which we code everything and then code the tests but this is usually a bad idea since it would cost more in time and it would be harder to trace errors since it is hard to isolate bugs, but it is also possible to test using an *Incremental Approach* [2] by developing the integration tests while working on the module, but to do so it is needed to input something similar to the output of the original module and the modules must agree beforehand their expected outputs and inputs, eg.: It is possible to test the Front API by faking the controller response and passing it as an input for the Front API.\n",
"\n",
"## Situational Examples\n",
"\n",
"Let's say that we are developing the controller but the Data Access Layer (DAL) and the Mailer Service are still under development, but we still need to test the controller somehow and to do so it is possible to use stubs to replace the DAL and the Mailer Service. Stubs are simple objects with pre-determined answers for certain executions durint the tests.\n",
"\n",
"Now we can assume that the Mailer Service and the DAL are under development but the controller is not ready yet, but we need to test the controller behavior on dealing with both modules. Using a Driver in this scenario may be the best option since the Driver is a provisional module that emulates the behavior of a module in a upper level and in this case it would emulate the Controller.\n",
"\n",
"## Techniques\n",
"\n",
"Depending on the language used on the project it is possible to have more or less flexibility on testing, for example, in Python there isn't a hard limitation for accessing private fields, so it is easy to access such fields and the language provides native support to do so, but on the other hand, JVM based languages such as Java, locks any kind of access to private fields during tests, but there are some frameworks that are able to tweak the generated bytecode during the compile in order to expose those fields only for testing. But in most languages it is possible to use some of the techniques detailed bellow.\n",
"\n",
"- Dummy objects with no funcionality that just needs to fill some space like filling parameters. In our sample mailer this could be done by implement a fake mailer service with the same interface as the original service but with no function and pre configured results.\n",
"- *Mocking* [3] is a technique that aims to create simulated version of objects related to your application in order to assert that the functions were called correctly or to simulate only certain functions of an implemented object. This could be used to mock the DAL access to a real database and return fake results only for testing purposes.\n",
"\n",
"## References\n",
"\n",
"1. Software Testing Dictionary. [Blog] Available at: <https://www.tutorialspoint.com/software_testing_dictionary/> [Accessed 10 August 2020].\n",
"2. What Is Incremental Testing: Detailed Explanation With Examples. [Blog] Available at: <https://www.softwaretestinghelp.com/incremental-testing/> [Accessed 10 August 2020].\n",
"3. Osherove, Roy (2009). \"Interaction testing with mock objects et seq\". The art of unit testing. Manning. ISBN 978-1-933988-27-6.\n",
"\n",
"\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
44 changes: 0 additions & 44 deletions testgranularity/integrationtesting.md

This file was deleted.