diff --git a/era5cli/cli.py b/era5cli/cli.py
index fadea62..f7cb0d7 100644
--- a/era5cli/cli.py
+++ b/era5cli/cli.py
@@ -425,10 +425,12 @@ def _execute(args):
         return True
 
 
-def main():
+def main(argv=None):
     """Main."""
     # get arguments
-    args = _parse_args(sys.argv[1:])
+    if argv is None:
+        argv = sys.argv
+    args = _parse_args(argv[1:])
     _execute(args)
 
 

diff --git a/tests/test_cli.py b/tests/test_cli.py
index 6390f32..1184ed1 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -1,4 +1,4 @@
-"""Tests for era5cli utility functios."""
+"""Tests for era5cli utility functions."""
 
 import unittest.mock as mock
 import pytest
diff --git a/tests/test_integration.py b/tests/test_integration.py
new file mode 100644
index 0000000..1055dbc
--- /dev/null
+++ b/tests/test_integration.py
@@ -0,0 +1,128 @@
+"""Tests to check the full era5cli workflow."""
+
+import logging
+import pytest
+
+from textwrap import dedent
+
+from era5cli.cli import main
+
+
+# combine calls with result and possible warning message
+call_result = [
+    {
+        # orography is translated to geopotential in the query
+        "call": dedent("""\
+            era5cli hourly --variables orography --startyear 2008 --dryrun
+            """),
+        "result": dedent("""\
+            reanalysis-era5-single-levels {'variable': 'geopotential', 'year':
+            2008, 'month': ['01', '02', '03', '04', '05', '06', '07', '08',
+            '09', '10', '11', '12'], 'time': ['00:00', '01:00', '02:00',
+            '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00',
+            '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00',
+            '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'],
+            'format': 'netcdf', 'product_type': 'reanalysis', 'day': ['01',
+            '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12',
+            '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23',
+            '24', '25', '26', '27', '28', '29', '30', '31']}
+            era5_orography_2008_hourly.nc"""),
+        "warn": "The variable 'orography' has been deprecated by CDS."
+    },
+    {
+        # geopotential needs '--levels surface' to be correctly interpreted
+        "call": dedent("""\
+            era5cli hourly --variables geopotential --startyear 2008 --dryrun
+            --levels surface"""),
+        "result": dedent("""\
+            reanalysis-era5-single-levels {'variable': 'geopotential', 'year':
+            2008, 'month': ['01', '02', '03', '04', '05', '06', '07', '08',
+            '09', '10', '11', '12'], 'time': ['00:00', '01:00', '02:00',
+            '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00',
+            '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00',
+            '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'],
+            'format': 'netcdf', 'product_type': 'reanalysis', 'day': ['01',
+            '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12',
+            '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23',
+            '24', '25', '26', '27', '28', '29', '30', '31']}
+            era5_geopotential_2008_hourly.nc"""),
+        "warn": "Getting variable from surface level data."
+    },
+    {
+        # without --levels surface, geopotential calls pressure level data
+        "call": dedent("""\
+            era5cli hourly --variables geopotential --startyear 2008
+            --dryrun"""),
+        "result": dedent("""\
+            reanalysis-era5-pressure-levels {'variable': 'geopotential',
+            'year': 2008, 'month': ['01', '02', '03', '04', '05', '06', '07',
+            '08', '09', '10', '11', '12'], 'time': ['00:00', '01:00', '02:00',
+            '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00',
+            '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00',
+            '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'],
+            'format': 'netcdf', 'pressure_level': [1, 2, 3, 5, 7, 10, 20, 30,
+            50, 70, 100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500,
+            550, 600, 650, 700, 750, 775, 800, 825, 850, 875, 900, 925, 950,
+            975, 1000], 'product_type': 'reanalysis', 'day': ['01', '02', '03',
+            '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14',
+            '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25',
+            '26', '27', '28', '29', '30', '31']}
+            era5_geopotential_2008_hourly.nc"""),
+        "warn": "Getting variable from pressure level data."
+    },
+    {
+        # preliminary-back-extension is combined with monthly-means
+        "call": dedent("""\
+            era5cli monthly --variables temperature --startyear 1960 --prelimbe
+            --dryrun"""),
+        "result": dedent("""\
+            reanalysis-era5-pressure-levels-monthly-means-preliminary-back-extension
+            {'variable': 'temperature', 'year': 1960, 'month': ['01', '02',
+            '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],
+            'time': ['00:00'], 'format': 'netcdf', 'pressure_level': [1, 2, 3,
+            5, 7, 10, 20, 30, 50, 70, 100, 125, 150, 175, 200, 225, 250, 300,
+            350, 400, 450, 500, 550, 600, 650, 700, 750, 775, 800, 825, 850,
+            875, 900, 925, 950, 975, 1000], 'product_type':
+            'reanalysis-monthly-means-of-daily-means'}
+            era5_temperature_1960_monthly.nc""")
+    },
+    {
+        # era5-Land is combined with monthly means
+        "call": dedent("""\
+            era5cli monthly --variables snow_cover --startyear 2008 --land
+            --dryrun"""),
+        "result": dedent("""\
+            reanalysis-era5-land-monthly-means {'variable': 'snow_cover',
+            'year': 2008, 'month': ['01', '02', '03', '04', '05', '06', '07',
+            '08', '09', '10', '11', '12'], 'time': ['00:00'], 'format':
+            'netcdf', 'product_type': 'monthly_averaged_reanalysis'}
+            era5-land_snow_cover_2008_monthly.nc""")
+    }
+]
+
+
+def clean_ids(call):
+    call = call.replace('\n', ' ')
+    call = call.replace('--dryrun', '')
+    return(call)
+
+
+ids = [clean_ids(item["call"]) for item in call_result]
+
+
+@pytest.mark.parametrize("call_result", call_result, ids=ids)
+def test_main(call_result, capsys, caplog):
+    call = call_result["call"].split()
+    result = call_result["result"].replace('\n', ' ') + '\n'
+    # until the actual fetch is monkeypatched, make sure the tests are dryruns
+    if '--dryrun' not in call:
+        pytest.fail('call must be a dryrun')
+    with caplog.at_level(logging.INFO):
+        main(call)
+    captured = capsys.readouterr().out
+    assert result == captured
+    try:
+        warn = call_result["warn"]
+        assert warn in caplog.text
+    except KeyError:
+        assert caplog.text == ''

Add integration tests
At the moment, we test era5cli in two ways:
- Test if arguments given on the command line are parsed correctly and entered correctly to the Fetch class (`test_cli.py`)
- Test if information given to the Fetch class result in a correct CDS query (`test_fetch.py`).

It would be good to also add integration tests that combine these two, where arguments are given and the final query is asserted. This would make it easier to write tests for the tool to assert correct behavior of the tool as a whole.
tests/test_integration.py::test_main[era5cli
tests/test_cli.py::test_parse_args tests/test_cli.py::test_area_argument tests/test_cli.py::test_period_args tests/test_cli.py::test_level_arguments tests/test_cli.py::test_main_fetch tests/test_cli.py::test_main_info