From 890537253cf235091816d27a5c2fb64943c8e34a Mon Sep 17 00:00:00 2001
From: Tim Graham <timograham@gmail.com>
Date: Thu, 4 May 2017 10:14:35 -0400
Subject: [PATCH] Made runtests.py run gis_tests only when using a GIS database
 backend.

This facilitates other changes like refs #28160.
---
 tests/gis_tests/distapp/models.py             |  1 -
 tests/gis_tests/distapp/tests.py              |  2 --
 tests/gis_tests/geo3d/models.py               |  2 --
 tests/gis_tests/geo3d/tests.py                |  4 +--
 tests/gis_tests/geoadmin/models.py            |  1 -
 tests/gis_tests/geoadmin/tests.py             |  3 +--
 tests/gis_tests/geoapp/models.py              | 15 +----------
 tests/gis_tests/geoapp/test_expressions.py    |  1 -
 tests/gis_tests/geoapp/test_feeds.py          |  5 +---
 tests/gis_tests/geoapp/test_functions.py      |  1 -
 tests/gis_tests/geoapp/test_regress.py        |  1 -
 tests/gis_tests/geoapp/test_serializers.py    |  3 +--
 tests/gis_tests/geoapp/test_sitemaps.py       |  5 +---
 tests/gis_tests/geoapp/tests.py               |  3 ---
 tests/gis_tests/geogapp/models.py             |  3 ---
 tests/gis_tests/geogapp/tests.py              |  2 --
 .../gis_migrations/migrations/0001_initial.py |  4 +--
 .../gis_tests/gis_migrations/test_commands.py |  3 +--
 .../gis_migrations/test_operations.py         | 12 ++++-----
 tests/gis_tests/inspectapp/models.py          |  6 -----
 tests/gis_tests/inspectapp/tests.py           |  2 --
 tests/gis_tests/layermap/models.py            |  6 -----
 tests/gis_tests/layermap/tests.py             |  4 +--
 tests/gis_tests/relatedapp/models.py          |  1 -
 tests/gis_tests/relatedapp/tests.py           |  1 -
 tests/gis_tests/test_geoforms.py              |  6 +----
 tests/runtests.py                             | 25 +++++++++++--------
 27 files changed, 31 insertions(+), 91 deletions(-)

diff --git a/tests/gis_tests/distapp/models.py b/tests/gis_tests/distapp/models.py
index 1a5ef2cf90..fcad6fc097 100644
--- a/tests/gis_tests/distapp/models.py
+++ b/tests/gis_tests/distapp/models.py
@@ -8,7 +8,6 @@ class NamedModel(models.Model):
 
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return self.name
diff --git a/tests/gis_tests/distapp/tests.py b/tests/gis_tests/distapp/tests.py
index 7865bc4d6c..70e1f98d20 100644
--- a/tests/gis_tests/distapp/tests.py
+++ b/tests/gis_tests/distapp/tests.py
@@ -14,7 +14,6 @@ from .models import (
 )
 
 
-@skipUnlessDBFeature("gis_enabled")
 class DistanceTest(TestCase):
     fixtures = ['initial']
 
@@ -238,7 +237,6 @@ Perimeter(geom1)                                |    OK              |      :-(
 '''  # NOQA
 
 
-@skipUnlessDBFeature("gis_enabled")
 class DistanceFunctionsTests(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/geo3d/models.py b/tests/gis_tests/geo3d/models.py
index b7d3257f99..2f3bb4419e 100644
--- a/tests/gis_tests/geo3d/models.py
+++ b/tests/gis_tests/geo3d/models.py
@@ -6,7 +6,6 @@ class NamedModel(models.Model):
 
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return self.name
@@ -45,7 +44,6 @@ class SimpleModel(models.Model):
 
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
 
 class Point2D(SimpleModel):
diff --git a/tests/gis_tests/geo3d/tests.py b/tests/gis_tests/geo3d/tests.py
index 505a749d48..39603d1249 100644
--- a/tests/gis_tests/geo3d/tests.py
+++ b/tests/gis_tests/geo3d/tests.py
@@ -93,7 +93,7 @@ class Geo3DLoadingHelper:
         Polygon3D.objects.create(name='3D BBox', poly=bbox_3d)
 
 
-@skipUnlessDBFeature("gis_enabled", "supports_3d_storage")
+@skipUnlessDBFeature("supports_3d_storage")
 class Geo3DTest(Geo3DLoadingHelper, TestCase):
     """
     Only a subset of the PostGIS routines are 3D-enabled, and this TestCase
@@ -204,7 +204,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
         self.assertIsNone(City3D.objects.none().aggregate(Extent3D('point'))['point__extent3d'])
 
 
-@skipUnlessDBFeature("gis_enabled", "supports_3d_functions")
+@skipUnlessDBFeature("supports_3d_functions")
 class Geo3DFunctionsTests(Geo3DLoadingHelper, TestCase):
     def test_kml(self):
         """
diff --git a/tests/gis_tests/geoadmin/models.py b/tests/gis_tests/geoadmin/models.py
index 9303dc1228..731753f50b 100644
--- a/tests/gis_tests/geoadmin/models.py
+++ b/tests/gis_tests/geoadmin/models.py
@@ -9,7 +9,6 @@ class City(models.Model):
 
     class Meta:
         app_label = 'geoadmin'
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return self.name
diff --git a/tests/gis_tests/geoadmin/tests.py b/tests/gis_tests/geoadmin/tests.py
index 96877c26e3..3bfbe2d3ed 100644
--- a/tests/gis_tests/geoadmin/tests.py
+++ b/tests/gis_tests/geoadmin/tests.py
@@ -1,13 +1,12 @@
 from django.contrib.gis import admin
 from django.contrib.gis.geos import Point
-from django.test import TestCase, override_settings, skipUnlessDBFeature
+from django.test import TestCase, override_settings
 from django.test.utils import patch_logger
 
 from .admin import UnmodifiableAdmin
 from .models import City, site
 
 
-@skipUnlessDBFeature("gis_enabled")
 @override_settings(ROOT_URLCONF='django.contrib.gis.tests.geoadmin.urls')
 class GeoAdminTest(TestCase):
 
diff --git a/tests/gis_tests/geoapp/models.py b/tests/gis_tests/geoapp/models.py
index b555165e56..9845524fb4 100644
--- a/tests/gis_tests/geoapp/models.py
+++ b/tests/gis_tests/geoapp/models.py
@@ -8,7 +8,6 @@ class NamedModel(models.Model):
 
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return self.name
@@ -27,7 +26,6 @@ class City(NamedModel):
 
     class Meta:
         app_label = 'geoapp'
-        required_db_features = ['gis_enabled']
 
 
 # This is an inherited model from City
@@ -37,7 +35,6 @@ class PennsylvaniaCity(City):
 
     class Meta:
         app_label = 'geoapp'
-        required_db_features = ['gis_enabled']
 
 
 class State(NamedModel):
@@ -45,7 +42,6 @@ class State(NamedModel):
 
     class Meta:
         app_label = 'geoapp'
-        required_db_features = ['gis_enabled']
 
 
 class Track(NamedModel):
@@ -57,9 +53,6 @@ class MultiFields(NamedModel):
     point = models.PointField()
     poly = models.PolygonField()
 
-    class Meta:
-        required_db_features = ['gis_enabled']
-
 
 class UniqueTogetherModel(models.Model):
     city = models.CharField(max_length=30)
@@ -67,15 +60,12 @@ class UniqueTogetherModel(models.Model):
 
     class Meta:
         unique_together = ('city', 'point')
-        required_db_features = ['gis_enabled', 'supports_geometry_field_unique_index']
+        required_db_features = ['supports_geometry_field_unique_index']
 
 
 class Truth(models.Model):
     val = models.BooleanField(default=False)
 
-    class Meta:
-        required_db_features = ['gis_enabled']
-
 
 class Feature(NamedModel):
     geom = models.GeometryField()
@@ -84,9 +74,6 @@ class Feature(NamedModel):
 class MinusOneSRID(models.Model):
     geom = models.PointField(srid=-1)  # Minus one SRID.
 
-    class Meta:
-        required_db_features = ['gis_enabled']
-
 
 class NonConcreteField(models.IntegerField):
 
diff --git a/tests/gis_tests/geoapp/test_expressions.py b/tests/gis_tests/geoapp/test_expressions.py
index 72f9a37dc4..496e6b58ce 100644
--- a/tests/gis_tests/geoapp/test_expressions.py
+++ b/tests/gis_tests/geoapp/test_expressions.py
@@ -9,7 +9,6 @@ from ..utils import postgis
 from .models import City, ManyPointModel
 
 
-@skipUnlessDBFeature('gis_enabled')
 class GeoExpressionsTests(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/geoapp/test_feeds.py b/tests/gis_tests/geoapp/test_feeds.py
index c8fd32802f..6ca49be471 100644
--- a/tests/gis_tests/geoapp/test_feeds.py
+++ b/tests/gis_tests/geoapp/test_feeds.py
@@ -2,16 +2,13 @@ from xml.dom import minidom
 
 from django.conf import settings
 from django.contrib.sites.models import Site
-from django.test import (
-    TestCase, modify_settings, override_settings, skipUnlessDBFeature,
-)
+from django.test import TestCase, modify_settings, override_settings
 
 from .models import City
 
 
 @modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
 @override_settings(ROOT_URLCONF='gis_tests.geoapp.urls')
-@skipUnlessDBFeature("gis_enabled")
 class GeoFeedTest(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py
index 6e4a87f212..ccb0dbb937 100644
--- a/tests/gis_tests/geoapp/test_functions.py
+++ b/tests/gis_tests/geoapp/test_functions.py
@@ -16,7 +16,6 @@ from ..utils import mysql, oracle, postgis, spatialite
 from .models import City, Country, CountryWebMercator, State, Track
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GISFunctionsTests(TestCase):
     """
     Testing functions from django/contrib/gis/db/models/functions.py.
diff --git a/tests/gis_tests/geoapp/test_regress.py b/tests/gis_tests/geoapp/test_regress.py
index 2d62349dbb..7c4eb7f4df 100644
--- a/tests/gis_tests/geoapp/test_regress.py
+++ b/tests/gis_tests/geoapp/test_regress.py
@@ -9,7 +9,6 @@ from ..utils import no_oracle
 from .models import City, PennsylvaniaCity, State, Truth
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeoRegressionTests(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/geoapp/test_serializers.py b/tests/gis_tests/geoapp/test_serializers.py
index 7f756e1544..4ec99c5de6 100644
--- a/tests/gis_tests/geoapp/test_serializers.py
+++ b/tests/gis_tests/geoapp/test_serializers.py
@@ -2,12 +2,11 @@ import json
 
 from django.contrib.gis.geos import LinearRing, Point, Polygon
 from django.core import serializers
-from django.test import TestCase, skipUnlessDBFeature
+from django.test import TestCase
 
 from .models import City, MultiFields, PennsylvaniaCity
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeoJSONSerializerTests(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/geoapp/test_sitemaps.py b/tests/gis_tests/geoapp/test_sitemaps.py
index 09df326bc6..69c097ea5d 100644
--- a/tests/gis_tests/geoapp/test_sitemaps.py
+++ b/tests/gis_tests/geoapp/test_sitemaps.py
@@ -4,16 +4,13 @@ from xml.dom import minidom
 
 from django.conf import settings
 from django.contrib.sites.models import Site
-from django.test import (
-    TestCase, modify_settings, override_settings, skipUnlessDBFeature,
-)
+from django.test import TestCase, modify_settings, override_settings
 
 from .models import City, Country
 
 
 @modify_settings(INSTALLED_APPS={'append': ['django.contrib.sites', 'django.contrib.sitemaps']})
 @override_settings(ROOT_URLCONF='gis_tests.geoapp.urls')
-@skipUnlessDBFeature("gis_enabled")
 class GeoSitemapTest(TestCase):
 
     def setUp(self):
diff --git a/tests/gis_tests/geoapp/tests.py b/tests/gis_tests/geoapp/tests.py
index 068b9f3de2..e5c728078f 100644
--- a/tests/gis_tests/geoapp/tests.py
+++ b/tests/gis_tests/geoapp/tests.py
@@ -20,7 +20,6 @@ from .models import (
 )
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeoModelTest(TestCase):
     fixtures = ['initial']
 
@@ -224,7 +223,6 @@ class GeoModelTest(TestCase):
             self.assertEqual(feature.geom.srid, g.srid)
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeoLookupTest(TestCase):
     fixtures = ['initial']
 
@@ -452,7 +450,6 @@ class GeoLookupTest(TestCase):
             self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeoQuerySetTest(TestCase):
     # TODO: GeoQuerySet is removed, organize these test better.
     fixtures = ['initial']
diff --git a/tests/gis_tests/geogapp/models.py b/tests/gis_tests/geogapp/models.py
index 3a658a6c47..6aa0b1f00e 100644
--- a/tests/gis_tests/geogapp/models.py
+++ b/tests/gis_tests/geogapp/models.py
@@ -6,7 +6,6 @@ class NamedModel(models.Model):
 
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return self.name
@@ -17,7 +16,6 @@ class City(NamedModel):
 
     class Meta:
         app_label = 'geogapp'
-        required_db_features = ['gis_enabled']
 
 
 class Zipcode(NamedModel):
@@ -31,7 +29,6 @@ class County(NamedModel):
 
     class Meta:
         app_label = 'geogapp'
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return ' County, '.join([self.name, self.state])
diff --git a/tests/gis_tests/geogapp/tests.py b/tests/gis_tests/geogapp/tests.py
index 3450847504..2969ca1cc6 100644
--- a/tests/gis_tests/geogapp/tests.py
+++ b/tests/gis_tests/geogapp/tests.py
@@ -15,7 +15,6 @@ from ..utils import oracle, postgis, spatialite
 from .models import City, County, Zipcode
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeographyTest(TestCase):
     fixtures = ['initial']
 
@@ -87,7 +86,6 @@ class GeographyTest(TestCase):
             self.assertEqual(state, c.state)
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeographyFunctionTests(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/gis_migrations/migrations/0001_initial.py b/tests/gis_tests/gis_migrations/migrations/0001_initial.py
index d92bb3b0e2..918b56554f 100644
--- a/tests/gis_tests/gis_migrations/migrations/0001_initial.py
+++ b/tests/gis_tests/gis_migrations/migrations/0001_initial.py
@@ -10,7 +10,6 @@ ops = [
             ('geom', models.MultiPolygonField(srid=4326)),
         ],
         options={
-            'required_db_features': ['gis_enabled'],
         },
         bases=(models.Model,),
     ),
@@ -29,7 +28,6 @@ ops = [
             ('geom', models.PointField(srid=4326, geography=True)),
         ],
         options={
-            'required_db_features': ['gis_enabled'],
         },
         bases=(models.Model,),
     ),
@@ -51,7 +49,7 @@ ops = [
     )
 ]
 
-if connection.features.gis_enabled and connection.features.supports_raster:
+if connection.features.supports_raster:
     ops += [
         migrations.CreateModel(
             name='Heatmap',
diff --git a/tests/gis_tests/gis_migrations/test_commands.py b/tests/gis_tests/gis_migrations/test_commands.py
index c9bf3773fe..cc89228585 100644
--- a/tests/gis_tests/gis_migrations/test_commands.py
+++ b/tests/gis_tests/gis_migrations/test_commands.py
@@ -1,9 +1,8 @@
 from django.core.management import call_command
 from django.db import connection
-from django.test import TransactionTestCase, skipUnlessDBFeature
+from django.test import TransactionTestCase
 
 
-@skipUnlessDBFeature("gis_enabled")
 class MigrateTests(TransactionTestCase):
     """
     Tests running the migrate command in Geodjango.
diff --git a/tests/gis_tests/gis_migrations/test_operations.py b/tests/gis_tests/gis_migrations/test_operations.py
index 31301ad4ca..3694a7eb67 100644
--- a/tests/gis_tests/gis_migrations/test_operations.py
+++ b/tests/gis_tests/gis_migrations/test_operations.py
@@ -12,15 +12,13 @@ from django.test import (
 
 from ..utils import mysql, spatialite
 
-if connection.features.gis_enabled:
-    try:
-        GeometryColumns = connection.ops.geometry_columns()
-        HAS_GEOMETRY_COLUMNS = True
-    except NotImplementedError:
-        HAS_GEOMETRY_COLUMNS = False
+try:
+    GeometryColumns = connection.ops.geometry_columns()
+    HAS_GEOMETRY_COLUMNS = True
+except NotImplementedError:
+    HAS_GEOMETRY_COLUMNS = False
 
 
-@skipUnlessDBFeature('gis_enabled')
 class OperationTestCase(TransactionTestCase):
     available_apps = ['gis_tests.gis_migrations']
 
diff --git a/tests/gis_tests/inspectapp/models.py b/tests/gis_tests/inspectapp/models.py
index 1319ed30e4..1c37579c0a 100644
--- a/tests/gis_tests/inspectapp/models.py
+++ b/tests/gis_tests/inspectapp/models.py
@@ -13,15 +13,9 @@ class AllOGRFields(models.Model):
     geom = models.PolygonField()
     point = models.PointField()
 
-    class Meta:
-        required_db_features = ['gis_enabled']
-
 
 class Fields3D(models.Model):
     point = models.PointField(dim=3)
     pointg = models.PointField(dim=3, geography=True)
     line = models.LineStringField(dim=3)
     poly = models.PolygonField(dim=3)
-
-    class Meta:
-        required_db_features = ['gis_enabled']
diff --git a/tests/gis_tests/inspectapp/tests.py b/tests/gis_tests/inspectapp/tests.py
index 43cf2c2d66..ec0be801db 100644
--- a/tests/gis_tests/inspectapp/tests.py
+++ b/tests/gis_tests/inspectapp/tests.py
@@ -18,7 +18,6 @@ if HAS_GDAL:
     from .models import AllOGRFields
 
 
-@skipUnlessDBFeature("gis_enabled")
 class InspectDbTests(TestCase):
     def test_geom_columns(self):
         """
@@ -61,7 +60,6 @@ class InspectDbTests(TestCase):
             self.assertIn('poly = models.GeometryField(', output)
 
 
-@skipUnlessDBFeature("gis_enabled")
 @modify_settings(
     INSTALLED_APPS={'append': 'django.contrib.gis'},
 )
diff --git a/tests/gis_tests/layermap/models.py b/tests/gis_tests/layermap/models.py
index 7bb7717fe8..9b05056f4e 100644
--- a/tests/gis_tests/layermap/models.py
+++ b/tests/gis_tests/layermap/models.py
@@ -6,7 +6,6 @@ class NamedModel(models.Model):
 
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
     def __str__(self):
         return self.name
@@ -35,7 +34,6 @@ class City(NamedModel):
 
     class Meta:
         app_label = 'layermap'
-        required_db_features = ['gis_enabled']
 
 
 class Interstate(NamedModel):
@@ -44,7 +42,6 @@ class Interstate(NamedModel):
 
     class Meta:
         app_label = 'layermap'
-        required_db_features = ['gis_enabled']
 
 
 # Same as `City` above, but for testing model inheritance.
@@ -71,9 +68,6 @@ class ICity2(ICity1):
 class Invalid(models.Model):
     point = models.PointField()
 
-    class Meta:
-        required_db_features = ['gis_enabled']
-
 
 # Mapping dictionaries for the models above.
 co_mapping = {
diff --git a/tests/gis_tests/layermap/tests.py b/tests/gis_tests/layermap/tests.py
index 09ff06c8a3..3e19697501 100644
--- a/tests/gis_tests/layermap/tests.py
+++ b/tests/gis_tests/layermap/tests.py
@@ -7,7 +7,7 @@ from django.conf import settings
 from django.contrib.gis.gdal import HAS_GDAL
 from django.contrib.gis.geos import HAS_GEOS
 from django.db import connection
-from django.test import TestCase, override_settings, skipUnlessDBFeature
+from django.test import TestCase, override_settings
 
 if HAS_GEOS and HAS_GDAL:
     from django.contrib.gis.utils.layermapping import (
@@ -34,7 +34,6 @@ NUMS = [1, 2, 1, 19, 1]  # Number of polygons for each.
 STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
 
 
-@skipUnlessDBFeature("gis_enabled")
 class LayerMapTest(TestCase):
 
     def test_init(self):
@@ -331,7 +330,6 @@ class OtherRouter:
         return True
 
 
-@skipUnlessDBFeature("gis_enabled")
 @override_settings(DATABASE_ROUTERS=[OtherRouter()])
 class LayerMapRouterTest(TestCase):
     multi_db = True
diff --git a/tests/gis_tests/relatedapp/models.py b/tests/gis_tests/relatedapp/models.py
index 749f39f74c..6903617a2a 100644
--- a/tests/gis_tests/relatedapp/models.py
+++ b/tests/gis_tests/relatedapp/models.py
@@ -4,7 +4,6 @@ from django.contrib.gis.db import models
 class SimpleModel(models.Model):
     class Meta:
         abstract = True
-        required_db_features = ['gis_enabled']
 
 
 class Location(SimpleModel):
diff --git a/tests/gis_tests/relatedapp/tests.py b/tests/gis_tests/relatedapp/tests.py
index 00bc2c6761..0a385f7625 100644
--- a/tests/gis_tests/relatedapp/tests.py
+++ b/tests/gis_tests/relatedapp/tests.py
@@ -12,7 +12,6 @@ from .models import (
 )
 
 
-@skipUnlessDBFeature("gis_enabled")
 class RelatedGeoModelTest(TestCase):
     fixtures = ['initial']
 
diff --git a/tests/gis_tests/test_geoforms.py b/tests/gis_tests/test_geoforms.py
index 91bfc173f5..c08ef308aa 100644
--- a/tests/gis_tests/test_geoforms.py
+++ b/tests/gis_tests/test_geoforms.py
@@ -4,12 +4,11 @@ from django.contrib.gis import forms
 from django.contrib.gis.forms import BaseGeometryWidget
 from django.contrib.gis.geos import GEOSGeometry
 from django.forms import ValidationError
-from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature
+from django.test import SimpleTestCase, override_settings
 from django.test.utils import patch_logger
 from django.utils.html import escape
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeometryFieldTest(SimpleTestCase):
 
     def test_init(self):
@@ -138,7 +137,6 @@ class GeometryFieldTest(SimpleTestCase):
         )
 
 
-@skipUnlessDBFeature("gis_enabled")
 class SpecializedFieldTest(SimpleTestCase):
     def setUp(self):
         self.geometries = {
@@ -310,7 +308,6 @@ class SpecializedFieldTest(SimpleTestCase):
             self.assertFalse(GeometryForm(data={'g': invalid.wkt}).is_valid())
 
 
-@skipUnlessDBFeature("gis_enabled")
 class OSMWidgetTest(SimpleTestCase):
     def setUp(self):
         self.geometries = {
@@ -351,7 +348,6 @@ class OSMWidgetTest(SimpleTestCase):
                 rendered)
 
 
-@skipUnlessDBFeature("gis_enabled")
 class GeometryWidgetTests(SimpleTestCase):
 
     def test_get_context_attrs(self):
diff --git a/tests/runtests.py b/tests/runtests.py
index cf07aef856..b05483526e 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -80,11 +80,12 @@ CONTRIB_TESTS_TO_APPS = {
 
 def get_test_modules():
     modules = []
-    discovery_paths = [
-        (None, RUNTESTS_DIR),
+    discovery_paths = [(None, RUNTESTS_DIR)]
+    if connection.features.gis_enabled:
         # GIS tests are in nested apps
-        ('gis_tests', os.path.join(RUNTESTS_DIR, 'gis_tests')),
-    ]
+        discovery_paths.append(('gis_tests', os.path.join(RUNTESTS_DIR, 'gis_tests')))
+    else:
+        SUBDIRS_TO_SKIP.append('gis_tests')
 
     for modpath, dirpath in discovery_paths:
         for f in os.listdir(dirpath):
@@ -102,6 +103,16 @@ def get_installed():
 
 
 def setup(verbosity, test_labels, parallel):
+    # Reduce the given test labels to just the app module path.
+    test_labels_set = set()
+    for label in test_labels:
+        bits = label.split('.')[:1]
+        test_labels_set.add('.'.join(bits))
+
+    if 'gis_tests' in test_labels_set and not connection.features.gis_enabled:
+        print('Aborting: A GIS database backend is required to run gis_tests.')
+        sys.exit(1)
+
     if verbosity >= 1:
         msg = "Testing against Django installed in '%s'" % os.path.dirname(django.__file__)
         max_parallel = default_test_processes() if parallel == 0 else parallel
@@ -169,12 +180,6 @@ def setup(verbosity, test_labels, parallel):
     # Load all the test model apps.
     test_modules = get_test_modules()
 
-    # Reduce given test labels to just the app module path
-    test_labels_set = set()
-    for label in test_labels:
-        bits = label.split('.')[:1]
-        test_labels_set.add('.'.join(bits))
-
     installed_app_names = set(get_installed())
     for modpath, module_name in test_modules:
         if modpath: