Fingest: Eein selbstentwickeltes pytest Plugin für bessere Test-Fixtures

Entdecken Sie fingest, ein selbstentwickeltes pytest Plugin für intelligente Dateibasierte Fixture-Verwaltung.

Einleitung

Als Entwickler bin ich täglich mit der Herausforderung konfrontiert, umfassende und wartbare Tests zu schreiben. Besonders bei datengetriebenen Tests stößt man schnell an die Grenzen traditioneller Ansätze. Aus diesem Grund habe ich Fingest entwickelt - ein pytest Plugin, das die Erstellung und Verwaltung von datengetriebenen Fixtures erheblich vereinfacht.

Was ist Fingest?

Fingest ist ein mächtiges pytest Plugin, das datengetriebene Tests ermöglicht, indem es automatisch Fixtures aus externen Datendateien erstellt. Der Name steht für "Fixture Ingest" und beschreibt perfekt, was das Plugin leistet: Es "verschlingt" Daten aus verschiedenen Quellen und macht sie als typisierte pytest-Fixtures verfügbar.

Die Motivation hinter Fingest

In meiner täglichen Arbeit als Python-Entwickler bin ich immer wieder auf folgende Probleme gestoßen:

🔄 Repetitive Fixture-Erstellung

# Traditioneller Ansatz - viel Boilerplate-Code
@pytest.fixture
def user_data():
    with open("tests/data/users.json") as f:
        return json.load(f)

@pytest.fixture  
def product_data():
    with open("tests/data/products.csv") as f:
        reader = csv.DictReader(f)
        return list(reader)

📁 Unstrukturierte Testdaten

  • Testdaten verstreut über verschiedene Dateien
  • Keine einheitliche Zugriffsmethoden
  • Schwierige Wartung und Aktualisierung

🎯 Fehlende Typisierung

  • Keine IDE-Unterstützung für Datenstrukturen
  • Laufzeitfehler durch falsche Annahmen über Datenformate
  • Schwierige Refaktorierung

Hauptfunktionen von Fingest

🚀 Automatische Fixture-Registrierung

Fingest erkennt automatisch Datendateien und erstellt entsprechende Fixtures:

from fingest import data_fixture, JSONFixture

@data_fixture("users.json", description="Test user data")
class user_data(JSONFixture):
    """Fixture für Benutzertestdaten."""
    pass

📁 Mehrere Datenformate unterstützt

  • JSON: Für strukturierte API-Daten und Konfigurationen
  • CSV: Für tabellarische Daten und Berichte
  • XML: Für Konfigurationsdateien und Legacy-Systeme
  • Erweiterbar: Eigene Datenloader für beliebige Formate

🎯 Typisierte Basis-Klassen

Jeder Datentyp erhält spezialisierte Methoden:

# JSON-spezifische Operationen
def test_json_operations(user_data):
    assert "users" in user_data.keys()
    user_count = user_data.get("user_count", 0)
    first_user = user_data["users"][0]

# CSV-spezifische Operationen  
def test_csv_operations(product_data):
    columns = product_data.columns
    prices = product_data.get_column("price")
    expensive_items = product_data.filter_rows(price="999.99")

# XML-spezifische Operationen
def test_xml_operations(config_data):
    timeout = config_data.find("timeout")
    features = config_data.findall("features/feature")
    enabled_features = config_data.xpath("//feature[@enabled='true']")

Installation und Setup

Installation

pip install fingest

Konfiguration in pytest.ini

[pytest]
fingest_fixture_path = tests/data  # Pfad zu Ihren Datendateien

Projektstruktur

my_project/
├── tests/
│   ├── data/
│   │   ├── users.json
│   │   ├── products.csv
│   │   └── config.xml
│   ├── conftest.py
│   └── test_*.py
└── pytest.ini

Praktische Beispiele

JSON-Fixtures für API-Tests

# tests/data/api_response.json
{
  "users": [
    {"id": 1, "name": "Alice", "email": "[email protected]", "active": true},
    {"id": 2, "name": "Bob", "email": "[email protected]", "active": false}
  ],
  "total_count": 2,
  "page": 1
}

# conftest.py
@data_fixture("api_response.json", description="API response data")
class api_data(JSONFixture):
    pass

# test_api.py
def test_user_count(api_data):
    assert len(api_data["users"]) == 2
    assert api_data.get("total_count") == 2

def test_active_users(api_data):
    active_users = [u for u in api_data["users"] if u["active"]]
    assert len(active_users) == 1
    assert active_users[0]["name"] == "Alice"

CSV-Fixtures für Datenanalyse

# tests/data/sales_data.csv
product_id,product_name,price,category,sales_count
1,Laptop,999.99,Electronics,150
2,Mouse,29.99,Electronics,300
3,Keyboard,79.99,Electronics,200

# conftest.py
@data_fixture("sales_data.csv", description="Sales analytics data")
class sales_data(CSVFixture):
    pass

# test_analytics.py
def test_product_categories(sales_data):
    categories = set(sales_data.get_column("category"))
    assert "Electronics" in categories

def test_price_analysis(sales_data):
    prices = [float(p) for p in sales_data.get_column("price")]
    assert max(prices) == 999.99
    assert min(prices) == 29.99

def test_high_value_products(sales_data):
    expensive = sales_data.filter_rows(price="999.99")
    assert len(expensive) == 1
    assert expensive[0]["product_name"] == "Laptop"

XML-Fixtures für Konfigurationstests

# tests/data/app_config.xml
<?xml version="1.0"?>
<config>
    <database>
        <host>localhost</host>
        <port>5432</port>
        <timeout>30</timeout>
    </database>
    <features>
        <feature name="auth" enabled="true"/>
        <feature name="cache" enabled="false"/>
        <feature name="logging" enabled="true"/>
    </features>
</config>

# conftest.py
@data_fixture("app_config.xml", description="Application configuration")
class app_config(XMLFixture):
    pass

# test_config.py
def test_database_config(app_config):
    host = app_config.get_text("database/host")
    port = int(app_config.get_text("database/port"))
    assert host == "localhost"
    assert port == 5432

def test_enabled_features(app_config):
    enabled_features = app_config.xpath("//feature[@enabled='true']")
    feature_names = [f.get("name") for f in enabled_features]
    assert "auth" in feature_names
    assert "logging" in feature_names
    assert "cache" not in feature_names

Erweiterte Funktionen

Funktionsbasierte Fixtures

Für komplexe Datenverarbeitung:

@data_fixture("raw_users.json", description="Processed user data")
def processed_users(data):
    """Transformiert rohe Benutzerdaten."""
    return [
        {
            "id": user["id"],
            "display_name": f"{user['first_name']} {user['last_name']}",
            "email": user["email"].lower(),
            "is_admin": user.get("role") == "admin"
        }
        for user in data["users"]
    ]

def test_processed_data(processed_users):
    assert processed_users[0]["display_name"] == "John Doe"
    assert "@" in processed_users[0]["email"]
    assert isinstance(processed_users[0]["is_admin"], bool)

Eigene Datenloader

Unterstützung für beliebige Dateiformate:

from fingest import register_loader
import yaml
import toml

# YAML-Support
def yaml_loader(path):
    with open(path, 'r') as f:
        return yaml.safe_load(f)

register_loader("yaml", yaml_loader)

@data_fixture("config.yaml", description="YAML configuration")
class yaml_config(BaseFixture):
    pass

# TOML-Support  
def toml_loader(path):
    with open(path, 'r') as f:
        return toml.load(f)

register_loader("toml", toml_loader)

Umgebungsspezifische Daten

import os
from fingest import data_fixture

env = os.getenv("TEST_ENV", "dev")

@data_fixture(f"config_{env}.json", description=f"Config for {env}")
class environment_config(JSONFixture):
    pass

# Lädt automatisch:
# - config_dev.json (Entwicklung)
# - config_staging.json (Staging)  
# - config_prod.json (Produktion)

Technische Details

Plugin-Architektur

Fingest nutzt pytest's Hook-System für nahtlose Integration:

# Automatische Registrierung über entry_points
[tool.poetry.plugins."pytest11"]
fingest = "fingest.plugin"

Datenloader-System

Erweiterbare Architektur für neue Formate:

# Eingebaute Loader
BUILTIN_LOADERS = {
    "json": json_loader,
    "csv": csv_loader, 
    "xml": xml_loader
}

# Registrierung eigener Loader
def register_loader(extension: str, loader_func: Callable):
    """Registriert einen benutzerdefinierten Datenloader."""
    CUSTOM_LOADERS[extension] = loader_func

Typisierung und IDE-Support

Vollständige Typisierung für bessere Entwicklererfahrung:

from typing import Dict, List, Any, Optional
from pathlib import Path

class BaseFixture:
    def __init__(self, data: Any) -> None: ...
    def __len__(self) -> int: ...
    def __bool__(self) -> bool: ...

class JSONFixture(BaseFixture):
    def get(self, key: str, default: Any = None) -> Any: ...
    def keys(self) -> Dict.KeysView: ...
    def values(self) -> Dict.ValuesView: ...

Qualitätssicherung

Umfassende Tests

  • 84 Tests mit 100% Erfolgsrate
  • Vollständige Abdeckung aller Funktionen
  • Integration Tests für alle unterstützten Formate
  • Performance Tests für große Datensätze

Code-Qualität

# Automatische Code-Formatierung
black src/ tests/
isort src/ tests/

# Linting und Typisierung  
flake8 src/ tests/
mypy src/

# Test-Ausführung mit Coverage
pytest --cov=fingest --cov-report=html

CI/CD Pipeline

# .github/workflows/test.yml
- name: Run tests
  run: |
    pytest --cov=fingest
    pytest --cov=fingest --cov-report=xml

- name: Code quality
  run: |
    black --check src/ tests/
    isort --check-only src/ tests/
    flake8 src/ tests/
    mypy src/

Vergleich mit traditionellen Ansätzen

Vorher (Traditionell)

import json
import csv
import xml.etree.ElementTree as ET

@pytest.fixture
def user_data():
    with open("tests/data/users.json") as f:
        return json.load(f)

@pytest.fixture
def product_data():
    with open("tests/data/products.csv") as f:
        reader = csv.DictReader(f)
        return list(reader)

@pytest.fixture
def config_data():
    tree = ET.parse("tests/data/config.xml")
    return tree.getroot()

def test_users(user_data):
    # Keine IDE-Unterstützung
    # Keine typisierte Methoden
    assert len(user_data["users"]) == 2

Nachher (Mit Fingest)

from fingest import data_fixture, JSONFixture, CSVFixture, XMLFixture

@data_fixture("users.json")
class user_data(JSONFixture): pass

@data_fixture("products.csv") 
class product_data(CSVFixture): pass

@data_fixture("config.xml")
class config_data(XMLFixture): pass

def test_users(user_data):
    # Vollständige IDE-Unterstützung
    # Typisierte Methoden verfügbar
    assert len(user_data["users"]) == 2
    assert user_data.get("total_count", 0) > 0

Performance und Skalierung

Lazy Loading

# Daten werden nur bei Bedarf geladen
@data_fixture("large_dataset.json")
class large_data(JSONFixture):
    pass

# Wird nur geladen, wenn der Test tatsächlich ausgeführt wird
def test_large_data(large_data):
    assert len(large_data) > 1000

Caching

# Automatisches Caching für bessere Performance
# Datei wird nur einmal pro Test-Session geladen
@data_fixture("shared_config.json", scope="session")
class shared_config(JSONFixture):
    pass

Zukunftspläne

Geplante Features

  • Datenvalidierung: Schema-Validierung für JSON/XML
  • Daten-Mocking: Automatische Generierung von Testdaten
  • Database-Support: Direkte Verbindung zu Datenbanken
  • Cloud-Integration: Support für S3, GCS, Azure Blob Storage
  • Performance-Optimierung: Paralleles Laden großer Datensätze

Community-Beiträge

# Beispiel für geplante Database-Integration
@data_fixture("SELECT * FROM users", loader=sql_loader)
class db_users(SQLFixture):
    pass

# Beispiel für Cloud-Integration  
@data_fixture("s3://bucket/data.json", loader=s3_loader)
class cloud_data(JSONFixture):
    pass

Fazit

Fingest revolutioniert die Art, wie wir datengetriebene Tests in Python schreiben. Durch die Kombination aus:

  • Automatischer Fixture-Registrierung
  • Typisierten Basis-Klassen
  • Erweiterbarer Architektur
  • Umfassender Dokumentation

wird das Schreiben und Warten von Tests erheblich vereinfacht. Das Plugin ist bereits produktionsreif und wird aktiv in mehreren Projekten eingesetzt.

Weiterführende Ressourcen

Installation und erste Schritte

# Installation
pip install fingest

# Beispiel-Projekt klonen
git clone https://github.com/0x68/fingest.git
cd fingest/examples

# Tests ausführen
pytest -v

Haben Sie Erfahrungen mit datengetriebenen Tests oder Interesse an Fingest? Ich freue mich über Feedback, Beiträge und Diskussionen! Kontaktieren Sie mich gerne über GitHub oder direkt per E-Mail.

Entwickelt mit ❤️ von Tim Fiedler

Ähnliche Beiträge

Professionelles Testen mit pytest: Mocking mit monkeypatch und create_autospec

Ein umfassender Leitfaden zum professionellen Testen mit pytest. Lernen Sie, wie Sie mit monkeypatch und create_autospec typsichere Mocks erstellen und …

01.07.2025

Über re-minds GmbH

Seit 2015 entwickeln wir maßgeschneiderte Software-Lösungen und begleiten Unternehmen bei ihrer digitalen Transformation. Unser Fokus liegt auf Python, Django und modernen Cloud-Technologien.

Entwicklung

Professionelle Web-Anwendungen mit Python, Django und modernen Frameworks

Cloud & DevOps

Skalierbare Cloud-Lösungen auf AWS, GCP und Azure mit CI/CD-Pipelines

Schulungen

Inhouse-Trainings für Python, Django, DevOps und moderne Entwicklungsmethoden

Kontakt aufnehmen

Unser Büro

re-minds GmbH
Alter Postweg 32
26215 Neuenkruge

Telefon

+49 151 404 183 93

E-Mail

[email protected]

Imprint

Angaben gemäß § 5 TMG:

re-minds GmbH
Waldweg 1A
26215 Wiefelstede

Kontakt:
+49 (0)151 – 40418393
[email protected]
www.re-minds.de

Registergericht: Oldenburg
Registernummer: HRB 216237
Vertretungsberechtigte Geschäftsführer: Tim Fiedler
Umsatzsteuer-Identifikationsnummer nach § 27a UStG:
DE338576407

Datenschutzerklärung

Allgemeiner Hinweis und Pflichtinformationen

Benennung der verantwortlichen Stelle

Die verantwortliche Stelle für die Datenverarbeitung auf dieser Website ist:

re-minds GmbH
Tim Fiedler
Alter Postweg 32
26215 Neuenkruge

Die verantwortliche Stelle entscheidet allein oder gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten (z.B. Namen, Kontaktdaten o. Ä.).

Widerruf Ihrer Einwilligung zur Datenverarbeitung

Nur mit Ihrer ausdrücklichen Einwilligung sind einige Vorgänge der Datenverarbeitung möglich. Ein Widerruf Ihrer bereits erteilten Einwilligung ist jederzeit möglich. Für den Widerruf genügt eine formlose Mitteilung per E-Mail. Die Rechtmäßigkeit der bis zum Widerruf erfolgten Datenverarbeitung bleibt vom Widerruf unberührt.

Recht auf Beschwerde bei der zuständigen Aufsichtsbehörde

Als Betroffener steht Ihnen im Falle eines datenschutzrechtlichen Verstoßes ein Beschwerderecht bei der zuständigen Aufsichtsbehörde zu. Zuständige Aufsichtsbehörde bezüglich datenschutzrechtlicher Fragen ist der Landesdatenschutzbeauftragte des Bundeslandes, in dem sich der Sitz unseres Unternehmens befindet. Der folgende Link stellt eine Liste der Datenschutzbeauftragten sowie deren Kontaktdaten bereit: https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html.

Recht auf Datenübertragbarkeit

Ihnen steht das Recht zu, Daten, die wir auf Grundlage Ihrer Einwilligung oder in Erfüllung eines Vertrags automatisiert verarbeiten, an sich oder an Dritte aushändigen zu lassen. Die Bereitstellung erfolgt in einem maschinenlesbaren Format. Sofern Sie die direkte Übertragung der Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist.

Recht auf Auskunft, Berichtigung, Sperrung, Löschung

Sie haben jederzeit im Rahmen der geltenden gesetzlichen Bestimmungen das Recht auf unentgeltliche Auskunft über Ihre gespeicherten personenbezogenen Daten, Herkunft der Daten, deren Empfänger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung, Sperrung oder Löschung dieser Daten. Diesbezüglich und auch zu weiteren Fragen zum Thema personenbezogene Daten können Sie sich jederzeit über die im Impressum aufgeführten Kontaktmöglichkeiten an uns wenden.

SSL- bzw. TLS-Verschlüsselung

Aus Sicherheitsgründen und zum Schutz der Übertragung vertraulicher Inhalte, die Sie an uns als Seitenbetreiber senden, nutzt unsere Website eine SSL-bzw. TLS-Verschlüsselung. Damit sind Daten, die Sie über diese Website übermitteln, für Dritte nicht mitlesbar. Sie erkennen eine verschlüsselte Verbindung an der „https://“ Adresszeile Ihres Browsers und am Schloss-Symbol in der Browserzeile.

Server-Log-Dateien

In Server-Log-Dateien erhebt und speichert der Provider der Website automatisch Informationen, die Ihr Browser automatisch an uns übermittelt. Dies sind:

  • Besuchte Seite auf unserer Domain
  • Datum und Uhrzeit der Serveranfrage
  • Browsertyp und Browserversion
  • Verwendetes Betriebssystem
  • Referrer URL
  • Hostname des zugreifenden Rechners
  • IP-Adresse

Es findet keine Zusammenführung dieser Daten mit anderen Datenquellen statt. Grundlage der Datenverarbeitung bildet Art. 6 Abs. 1 lit. b DSGVO, der die Verarbeitung von Daten zur Erfüllung eines Vertrags oder vorvertraglicher Maßnahmen gestattet.

Kontaktformular

Per Kontaktformular übermittelte Daten werden einschließlich Ihrer Kontaktdaten gespeichert, um Ihre Anfrage bearbeiten zu können oder um für Anschlussfragen bereitzustehen. Eine Weitergabe dieser Daten findet ohne Ihre Einwilligung nicht statt.

Die Verarbeitung der in das Kontaktformular eingegebenen Daten erfolgt ausschließlich auf Grundlage Ihrer Einwilligung (Art. 6 Abs. 1 lit. a DSGVO). Ein Widerruf Ihrer bereits erteilten Einwilligung ist jederzeit möglich. Für den Widerruf genügt eine formlose Mitteilung per E-Mail. Die Rechtmäßigkeit der bis zum Widerruf erfolgten Datenverarbeitungsvorgänge bleibt vom Widerruf unberührt.

Über das Kontaktformular übermittelte Daten verbleiben bei uns, bis Sie uns zur Löschung auffordern, Ihre Einwilligung zur Speicherung widerrufen oder keine Notwendigkeit der Datenspeicherung mehr besteht. Zwingende gesetzliche Bestimmungen - insbesondere Aufbewahrungsfristen - bleiben unberührt.

Cookies

Unsere Website verwendet Cookies. Das sind kleine Textdateien, die Ihr Webbrowser auf Ihrem Endgerät speichert. Cookies helfen uns dabei, unser Angebot nutzerfreundlicher, effektiver und sicherer zu machen.

Einige Cookies sind “Session-Cookies.” Solche Cookies werden nach Ende Ihrer Browser-Sitzung von selbst gelöscht. Hingegen bleiben andere Cookies auf Ihrem Endgerät bestehen, bis Sie diese selbst löschen. Solche Cookies helfen uns, Sie bei Rückkehr auf unserer Website wiederzuerkennen.

Mit einem modernen Webbrowser können Sie das Setzen von Cookies überwachen, einschränken oder unterbinden. Viele Webbrowser lassen sich so konfigurieren, dass Cookies mit dem Schließen des Programms von selbst gelöscht werden. Die Deaktivierung von Cookies kann eine eingeschränkte Funktionalität unserer Website zur Folge haben.

Das Setzen von Cookies, die zur Ausübung elektronischer Kommunikationsvorgänge oder der Bereitstellung bestimmter, von Ihnen erwünschter Funktionen (z.B. Warenkorb) notwendig sind, erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Als Betreiber dieser Website haben wir ein berechtigtes Interesse an der Speicherung von Cookies zur technisch fehlerfreien und reibungslosen Bereitstellung unserer Dienste. Sofern die Setzung anderer Cookies (z.B. für Analyse-Funktionen) erfolgt, werden diese in dieser Datenschutzerklärung separat behandelt.

Google Analytics

Unsere Website verwendet Funktionen des Webanalysedienstes Google Analytics. Anbieter des Webanalysedienstes ist die Google Inc., 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA.

Google Analytics verwendet "Cookies." Das sind kleine Textdateien, die Ihr Webbrowser auf Ihrem Endgerät speichert und eine Analyse der Website-Benutzung ermöglichen. Mittels Cookie erzeugte Informationen über Ihre Benutzung unserer Website werden an einen Server von Google übermittelt und dort gespeichert. Server-Standort ist im Regelfall die USA.

Das Setzen von Google-Analytics-Cookies erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Als Betreiber dieser Website haben wir  ein berechtigtes Interesse an der Analyse des Nutzerverhaltens, um unser Webangebot und ggf. auch Werbung zu optimieren.

IP-Anonymisierung

Wir setzen Google Analytics in Verbindung mit der Funktion IP-Anonymisierung ein. Sie gewährleistet, dass Google Ihre IP-Adresse innerhalb von Mitgliedstaaten der Europäischen Union oder in anderen Vertragsstaaten des Abkommens über den Europäischen Wirtschaftsraum vor der Übermittlung in die USA kürzt. Es kann Ausnahmefälle geben, in denen Google die volle IP-Adresse an einen Server in den USA überträgt und dort kürzt. In unserem Auftrag wird Google diese Informationen benutzen, um Ihre Nutzung der Website auszuwerten, um Reports über Websiteaktivitäten zu erstellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen gegenüber uns zu erbringen. Es findet keine Zusammenführung der von Google Analytics übermittelten IP-Adresse mit anderen Daten von Google statt.

Browser Plugin

Das Setzen von Cookies durch Ihren Webbrowser ist verhinderbar. Einige Funktionen unserer Website könnten dadurch jedoch eingeschränkt werden. Ebenso können Sie die Erfassung von Daten bezüglich Ihrer Website-Nutzung einschließlich Ihrer IP-Adresse mitsamt anschließender Verarbeitung durch Google unterbinden. Dies ist möglich, indem Sie das über folgenden Link erreichbare Browser-Plugin herunterladen und installieren: https://tools.google.com/dlpage/gaoptout?hl=de.

Widerspruch gegen die Datenerfassung

Sie können die Erfassung Ihrer Daten durch Google Analytics verhindern, indem Sie auf folgenden Link klicken. Es wird ein Opt-Out-Cookie gesetzt, der die Erfassung Ihrer Daten bei zukünftigen Besuchen unserer Website verhindert: Google Analytics deaktivieren.

Einzelheiten zum Umgang mit Nutzerdaten bei Google Analytics finden Sie in der Datenschutzerklärung von Google: https://support.google.com/analytics/answer/6004245?hl=de.

Auftragsverarbeitung

Zur vollständigen Erfüllung der gesetzlichen Datenschutzvorgaben haben wir mit Google einen Vertrag über die Auftragsverarbeitung abgeschlossen.

Demografische Merkmale bei Google Analytics

Unsere Website verwendet die Funktion “demografische Merkmale” von Google Analytics. Mit ihr lassen sich Berichte erstellen, die Aussagen zu Alter, Geschlecht und Interessen der Seitenbesucher enthalten. Diese Daten stammen aus interessenbezogener Werbung von Google sowie aus Besucherdaten von Drittanbietern. Eine Zuordnung der Daten zu einer bestimmten Person ist nicht möglich. Sie können diese Funktion jederzeit deaktivieren. Dies ist über die Anzeigeneinstellungen in Ihrem Google-Konto möglich oder indem Sie die Erfassung Ihrer Daten durch Google Analytics, wie im Punkt “Widerspruch gegen die Datenerfassung” erläutert, generell untersagen.

Quelle: Datenschutz-Konfigurator von mein-datenschutzbeauftragter.de

hier Google Analytics Tracking für diese Website abschalten