diff --git a/meson.build b/meson.build
index 37fe9ce4..99174b6e 100644
--- a/meson.build
+++ b/meson.build
@@ -241,9 +241,12 @@ else
     pipelines = wanted_pipelines
 endif
 
-# Tests require the vimc pipeline handler, include it automatically when tests
-# are enabled.
-if get_option('test')
+test_unit_enabled = get_option('test') or get_option('test-unit')
+test_integration_enabled = get_option('test') or get_option('test-integration')
+
+# Integration tests require the vimc pipeline handler, include it automatically
+# when they are enabled.
+if test_integration_enabled
     foreach pipeline, archs : pipelines_support
         if 'test' in archs and pipeline not in pipelines
             message('Enabling ' + pipeline + ' pipeline handler for tests')
@@ -304,7 +307,8 @@ summary({
             'GStreamer support': gst_enabled,
             'Python bindings': pycamera_enabled,
             'V4L2 emulation support': v4l2_enabled,
-            'Unit tests': test_enabled,
+            'Unit tests': test_unit_enabled,
+            'Integration tests': test_integration_enabled,
         },
         section : 'Configuration',
         bool_yn : true)
diff --git a/meson_options.txt b/meson_options.txt
index e829ebe6..fffdb6de 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -114,7 +114,17 @@ option('softisp-gpu',
 option('test',
         type : 'boolean',
         value : false,
-        description : 'Compile and include the tests')
+        description : 'Compile and include all tests')
+
+option('test-unit',
+        type : 'boolean',
+        value : false,
+        description : 'Compile and include unit tests')
+
+option('test-integration',
+        type : 'boolean',
+        value : false,
+        description : 'Compile and include integration tests')
 
 option('tracing',
         type : 'feature',
diff --git a/src/ipa/meson.build b/src/ipa/meson.build
index ab4a1897..200fad8d 100644
--- a/src/ipa/meson.build
+++ b/src/ipa/meson.build
@@ -36,9 +36,9 @@ supported_ipas = {
 
 ipa_modules = get_option('ipas')
 
-# Tests require the vimc IPA, similar to vimc pipline-handler for their
-# execution. Include it automatically when tests are enabled.
-if get_option('test') and 'vimc' not in ipa_modules
+# Integration tests require the vimc IPA, similar to the vimc pipeline
+# handler. Include it automatically when integration tests are enabled.
+if test_integration_enabled and 'vimc' not in ipa_modules
     message('Enabling vimc IPA to support tests')
     ipa_modules += ['vimc']
 endif
diff --git a/test/camera/meson.build b/test/camera/meson.build
index b92e16de..419915ef 100644
--- a/test/camera/meson.build
+++ b/test/camera/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 # Tests are listed in order of complexity.
 # They are not alphabetically sorted.
 camera_tests = [
diff --git a/test/controls/meson.build b/test/controls/meson.build
index cab33717..745212df 100644
--- a/test/controls/meson.build
+++ b/test/controls/meson.build
@@ -8,6 +8,10 @@ control_tests = [
 ]
 
 foreach test : control_tests
+    if test.get('suite', 'unit') not in test_suites
+        continue
+    endif
+
     exe = executable(test['name'], test['sources'],
                      dependencies : libcamera_public,
                      link_with : test_libraries,
diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
index 249cf933..4fd7a530 100644
--- a/test/gstreamer/meson.build
+++ b/test/gstreamer/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 if not gst_enabled
     subdir_done()
 endif
diff --git a/test/integration/meson.build b/test/integration/meson.build
new file mode 100644
index 00000000..51e97101
--- /dev/null
+++ b/test/integration/meson.build
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: CC0-1.0
+
+# Integration test subdirectories register tests in the 'integration' suite.
diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build
index c3c542b6..d6f13323 100644
--- a/test/ipa/libipa/meson.build
+++ b/test/ipa/libipa/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_unit_enabled
+    subdir_done()
+endif
+
 libipa_test = [
     {'name': 'fixedpoint', 'sources': ['fixedpoint.cpp']},
     {'name': 'histogram', 'sources': ['histogram.cpp']},
diff --git a/test/ipa/meson.build b/test/ipa/meson.build
index 08067092..9faace7e 100644
--- a/test/ipa/meson.build
+++ b/test/ipa/meson.build
@@ -2,6 +2,10 @@
 
 subdir('libipa')
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 ipa_test = [
     {'name': 'ipa_module_test', 'sources': ['ipa_module_test.cpp']},
     {'name': 'ipa_interface_test', 'sources': ['ipa_interface_test.cpp']},
diff --git a/test/ipc/meson.build b/test/ipc/meson.build
index 394a87c1..e7edd236 100644
--- a/test/ipc/meson.build
+++ b/test/ipc/meson.build
@@ -6,6 +6,10 @@ ipc_tests = [
 ]
 
 foreach test : ipc_tests
+    if test.get('suite', 'unit') not in test_suites
+        continue
+    endif
+
     exe = executable(test['name'], test['sources'],
                      dependencies : libcamera_private,
                      link_with : test_libraries,
diff --git a/test/log/meson.build b/test/log/meson.build
index 468e70db..44b25f25 100644
--- a/test/log/meson.build
+++ b/test/log/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_unit_enabled
+    subdir_done()
+endif
+
 log_test = [
     {'name': 'log_api', 'sources': ['log_api.cpp']},
     {'name': 'log_process', 'sources': ['log_process.cpp']},
diff --git a/test/media_device/meson.build b/test/media_device/meson.build
index 7a8a6520..a5873abc 100644
--- a/test/media_device/meson.build
+++ b/test/media_device/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 lib_mdev_test_sources = files([
     'media_device_test.cpp',
 ])
diff --git a/test/meson.build b/test/meson.build
index 99ff5e84..79f4b1b7 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -1,11 +1,16 @@
 # SPDX-License-Identifier: CC0-1.0
 
-if not get_option('test')
-    test_enabled = false
-    subdir_done()
+test_suites = []
+if test_unit_enabled
+    test_suites += 'unit'
+endif
+if test_integration_enabled
+    test_suites += 'integration'
 endif
 
-test_enabled = true
+if test_suites.length() == 0
+    subdir_done()
+endif
 
 # When ASan is enabled, find the path to the ASan runtime needed by multiple
 # tests. This currently works with gcc only, as clang uses different file names
@@ -25,6 +30,10 @@ endif
 
 subdir('libtest')
 
+if test_integration_enabled
+    subdir('integration')
+endif
+
 subdir('camera')
 subdir('controls')
 subdir('gstreamer')
@@ -86,6 +95,10 @@ internal_non_parallel_tests = [
 ]
 
 foreach test : public_tests
+    if not test_unit_enabled
+        continue
+    endif
+
     deps = [libcamera_public]
     if 'dependencies' in test
         deps += test['dependencies']
@@ -103,6 +116,10 @@ foreach test : public_tests
 endforeach
 
 foreach test : internal_tests
+    if test.get('suite', 'unit') not in test_suites
+        continue
+    endif
+
     deps = [libcamera_private]
     if 'dependencies' in test
         deps += test['dependencies']
@@ -120,6 +137,10 @@ foreach test : internal_tests
 endforeach
 
 foreach test : internal_non_parallel_tests
+    if not test_integration_enabled
+        continue
+    endif
+
     deps = [libcamera_private]
     if 'dependencies' in test
         deps += test['dependencies']
diff --git a/test/process/meson.build b/test/process/meson.build
index d40b3e74..4e2cc982 100644
--- a/test/process/meson.build
+++ b/test/process/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_unit_enabled
+    subdir_done()
+endif
+
 process_tests = [
     {'name': 'process_test', 'sources': ['process_test.cpp']},
 ]
diff --git a/test/py/meson.build b/test/py/meson.build
index c35209df..45194abd 100644
--- a/test/py/meson.build
+++ b/test/py/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 if not pycamera_enabled
     subdir_done()
 endif
diff --git a/test/serialization/generated_serializer/meson.build b/test/serialization/generated_serializer/meson.build
index 6595164c..b6271370 100644
--- a/test/serialization/generated_serializer/meson.build
+++ b/test/serialization/generated_serializer/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_unit_enabled
+    subdir_done()
+endif
+
 subdir('include/libcamera/ipa')
 
 exe = executable('generated_serializer_test',
diff --git a/test/serialization/meson.build b/test/serialization/meson.build
index 77cfa8c3..d786b8da 100644
--- a/test/serialization/meson.build
+++ b/test/serialization/meson.build
@@ -2,6 +2,10 @@
 
 subdir('generated_serializer')
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 serialization_tests = [
     {'name': 'control_serialization', 'sources': ['control_serialization.cpp']},
     {'name': 'ipa_data_serializer_test', 'sources': ['ipa_data_serializer_test.cpp']},
diff --git a/test/software_isp/meson.build b/test/software_isp/meson.build
index 539278ad..c49ab8ac 100644
--- a/test/software_isp/meson.build
+++ b/test/software_isp/meson.build
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: CC0-1.0
 
-if not softisp_enabled
+if not test_unit_enabled or not softisp_enabled
     subdir_done()
 endif
 
diff --git a/test/stream/meson.build b/test/stream/meson.build
index dc9468c7..c7cf7c5a 100644
--- a/test/stream/meson.build
+++ b/test/stream/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_unit_enabled
+    subdir_done()
+endif
+
 stream_tests = [
     {'name': 'stream_colorspace', 'sources': ['stream_colorspace.cpp']},
     {'name': 'stream_formats', 'sources': ['stream_formats.cpp']},
diff --git a/test/v4l2_compat/meson.build b/test/v4l2_compat/meson.build
index 01045a83..38be3971 100644
--- a/test/v4l2_compat/meson.build
+++ b/test/v4l2_compat/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 if not is_variable('v4l2_compat')
     subdir_done()
 endif
diff --git a/test/v4l2_subdevice/meson.build b/test/v4l2_subdevice/meson.build
index 68255717..59f4e5ec 100644
--- a/test/v4l2_subdevice/meson.build
+++ b/test/v4l2_subdevice/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 v4l2_subdevice_tests = [
     {'name': 'list_formats', 'sources': ['list_formats.cpp']},
     {'name': 'test_formats', 'sources': ['test_formats.cpp']},
diff --git a/test/v4l2_videodevice/meson.build b/test/v4l2_videodevice/meson.build
index 486e831c..3be95651 100644
--- a/test/v4l2_videodevice/meson.build
+++ b/test/v4l2_videodevice/meson.build
@@ -1,5 +1,9 @@
 # SPDX-License-Identifier: CC0-1.0
 
+if not test_integration_enabled
+    subdir_done()
+endif
+
 # Tests are listed in order of complexity.
 # They are not alphabetically sorted.
 v4l2_videodevice_tests = [
