Repository: ClearcodeHQ/pytest-mysql (language: python)

Issue:
Is it possible to execute test on a already running mysql service?
The mysql service is spined by vagrant in a guest machine with a configured port forwarding
There is no need for spinning a mysql service on the host machine.


Discussion / hints:
not at the moment

Although the solution is basically ready, one would have to just copy/adjust solution prepare ie in here:
https://github.com/ClearcodeHQ/pytest-postgresql/pull/247
Thank @fizyk. I have moved forward and implemented a fixture which addresses my use case.

Fix patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index d912b9c7..8d3eb9d0 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,12 @@ CHANGELOG
 unreleased
 ----------
 
+Feature
++++++++
+
+- `mysql_noproc` fixture to connect to already running mysql server
+
+
 Deprecation
 +++++++++++
 
diff --git a/README.rst b/README.rst
index 5413ed3d..0964cc61 100644
--- a/README.rst
+++ b/README.rst
@@ -227,6 +227,42 @@ Sample below is simplified session fixture from
     See the original code at `pyramid_fullauth's conftest file <https://github.com/fizyk/pyramid_fullauth/blob/2950e7f4a397b313aaf306d6d1a763ab7d8abf2b/tests/conftest.py#L35>`_.
     Depending on your needs, that in between code can fire alembic migrations in case of sqlalchemy stack or any other code
 
+Connecting to MySQL/MariaDB (in a docker)
+-----------------------------------------
+
+To connect to a docker run postgresql and run test on it, use noproc fixtures.
+
+.. code-block:: sh
+
+    docker run --name some-db -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d mysql --expose 3306
+
+.. code-block:: sh
+
+    docker run --name some-db -e MARIADB_ALLOW_EMPTY_PASSWORD=yes -d mariadb --expose 3306
+
+This will start postgresql in a docker container, however using a postgresql installed locally is not much different.
+
+In tests, make sure that all your tests are using **mysql_noproc** fixture like that:
+
+.. code-block:: python
+
+    mysql_in_docker = factories.mysql_noproc()
+    mysql = factories.mysql("mysql_in_docker")
+
+
+    def test_mysql_docker(mysql):
+        """Run test."""
+        cur = mysql.cursor()
+        cur.query("CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20), species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);")
+        mysql.commit()
+        cur.close()
+
+And run tests:
+
+.. code-block:: sh
+
+    pytest --mysql-host=127.0.0.1
+
 
 
 Running on Docker/as root
diff --git a/coverage-noproc.xml b/coverage-noproc.xml
new file mode 100644
index 00000000..0da7bb8b
--- /dev/null
+++ b/coverage-noproc.xml
@@ -0,0 +1,386 @@
+<?xml version="1.0" ?>
+<coverage version="5.5" timestamp="1622216804416" lines-valid="299" lines-covered="62" line-rate="0.2074" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0">
+	<!-- Generated by coverage.py: https://coverage.readthedocs.io -->
+	<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
+	<sources>
+		<source>/home/fizyk/workspace/pytest/pytest-mysql/src/pytest_mysql</source>
+		<source>/home/fizyk/workspace/pytest/pytest-mysql/tests</source>
+	</sources>
+	<packages>
+		<package name="." line-rate="0.2113" branch-rate="0" complexity="0">
+			<classes>
+				<class name="__init__.py" filename="__init__.py" complexity="0" line-rate="1" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="2" hits="1"/>
+					</lines>
+				</class>
+				<class name="config.py" filename="config.py" complexity="0" line-rate="0.875" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="1" hits="0"/>
+						<line number="3" hits="1"/>
+						<line number="4" hits="1"/>
+						<line number="17" hits="1"/>
+						<line number="18" hits="1"/>
+						<line number="19" hits="1"/>
+						<line number="22" hits="1"/>
+						<line number="23" hits="1"/>
+					</lines>
+				</class>
+				<class name="conftest.py" filename="conftest.py" complexity="0" line-rate="0.8889" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="2" hits="1"/>
+						<line number="3" hits="1"/>
+						<line number="5" hits="1"/>
+						<line number="7" hits="1"/>
+						<line number="8" hits="0"/>
+						<line number="12" hits="1"/>
+						<line number="13" hits="1"/>
+						<line number="14" hits="1"/>
+						<line number="15" hits="1"/>
+					</lines>
+				</class>
+				<class name="executor.py" filename="executor.py" complexity="0" line-rate="0" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="2" hits="0"/>
+						<line number="3" hits="0"/>
+						<line number="4" hits="0"/>
+						<line number="6" hits="0"/>
+						<line number="9" hits="0"/>
+						<line number="13" hits="0"/>
+						<line number="16" hits="0"/>
+						<line number="18" hits="0"/>
+						<line number="21" hits="0"/>
+						<line number="24" hits="0"/>
+						<line number="25" hits="0"/>
+						<line number="27" hits="0"/>
+						<line number="57" hits="0"/>
+						<line number="58" hits="0"/>
+						<line number="59" hits="0"/>
+						<line number="60" hits="0"/>
+						<line number="61" hits="0"/>
+						<line number="62" hits="0"/>
+						<line number="63" hits="0"/>
+						<line number="64" hits="0"/>
+						<line number="65" hits="0"/>
+						<line number="66" hits="0"/>
+						<line number="67" hits="0"/>
+						<line number="68" hits="0"/>
+						<line number="78" hits="0"/>
+						<line number="80" hits="0"/>
+						<line number="82" hits="0"/>
+						<line number="85" hits="0"/>
+						<line number="86" hits="0"/>
+						<line number="87" hits="0"/>
+						<line number="88" hits="0"/>
+						<line number="90" hits="0"/>
+						<line number="92" hits="0"/>
+						<line number="95" hits="0"/>
+						<line number="96" hits="0"/>
+						<line number="97" hits="0"/>
+						<line number="99" hits="0"/>
+						<line number="112" hits="0"/>
+						<line number="113" hits="0"/>
+						<line number="114" hits="0"/>
+						<line number="119" hits="0"/>
+						<line number="120" hits="0"/>
+						<line number="122" hits="0"/>
+						<line number="135" hits="0"/>
+						<line number="136" hits="0"/>
+						<line number="137" hits="0"/>
+						<line number="141" hits="0"/>
+						<line number="142" hits="0"/>
+						<line number="144" hits="0"/>
+						<line number="146" hits="0"/>
+						<line number="147" hits="0"/>
+						<line number="150" hits="0"/>
+						<line number="151" hits="0"/>
+						<line number="152" hits="0"/>
+						<line number="153" hits="0"/>
+						<line number="155" hits="0"/>
+						<line number="157" hits="0"/>
+						<line number="160" hits="0"/>
+						<line number="162" hits="0"/>
+						<line number="164" hits="0"/>
+						<line number="167" hits="0"/>
+						<line number="169" hits="0"/>
+						<line number="171" hits="0"/>
+						<line number="172" hits="0"/>
+					</lines>
+				</class>
+				<class name="executor_noop.py" filename="executor_noop.py" complexity="0" line-rate="0.5" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="1" hits="0"/>
+						<line number="2" hits="0"/>
+						<line number="8" hits="1"/>
+						<line number="9" hits="1"/>
+						<line number="10" hits="1"/>
+						<line number="11" hits="1"/>
+						<line number="13" hits="0"/>
+						<line number="15" hits="1"/>
+						<line number="17" hits="0"/>
+						<line number="19" hits="1"/>
+						<line number="21" hits="0"/>
+						<line number="23" hits="0"/>
+					</lines>
+				</class>
+				<class name="plugin.py" filename="plugin.py" complexity="0" line-rate="0" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="18" hits="0"/>
+						<line number="19" hits="0"/>
+						<line number="21" hits="0"/>
+						<line number="24" hits="0"/>
+						<line number="25" hits="0"/>
+						<line number="26" hits="0"/>
+						<line number="29" hits="0"/>
+						<line number="30" hits="0"/>
+						<line number="31" hits="0"/>
+						<line number="32" hits="0"/>
+						<line number="33" hits="0"/>
+						<line number="34" hits="0"/>
+						<line number="35" hits="0"/>
+						<line number="36" hits="0"/>
+						<line number="39" hits="0"/>
+						<line number="41" hits="0"/>
+						<line number="43" hits="0"/>
+						<line number="47" hits="0"/>
+						<line number="49" hits="0"/>
+						<line number="55" hits="0"/>
+						<line number="57" hits="0"/>
+						<line number="63" hits="0"/>
+						<line number="65" hits="0"/>
+						<line number="67" hits="0"/>
+						<line number="69" hits="0"/>
+						<line number="71" hits="0"/>
+						<line number="76" hits="0"/>
+						<line number="84" hits="0"/>
+						<line number="92" hits="0"/>
+						<line number="100" hits="0"/>
+						<line number="108" hits="0"/>
+						<line number="115" hits="0"/>
+						<line number="119" hits="0"/>
+						<line number="123" hits="0"/>
+						<line number="127" hits="0"/>
+						<line number="131" hits="0"/>
+						<line number="135" hits="0"/>
+						<line number="144" hits="0"/>
+						<line number="145" hits="0"/>
+						<line number="146" hits="0"/>
+					</lines>
+				</class>
+				<class name="port.py" filename="port.py" complexity="0" line-rate="0.1071" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="18" hits="0"/>
+						<line number="19" hits="0"/>
+						<line number="21" hits="0"/>
+						<line number="24" hits="0"/>
+						<line number="27" hits="0"/>
+						<line number="29" hits="0"/>
+						<line number="40" hits="0"/>
+						<line number="59" hits="1"/>
+						<line number="60" hits="0"/>
+						<line number="61" hits="1"/>
+						<line number="62" hits="1"/>
+						<line number="64" hits="0"/>
+						<line number="65" hits="0"/>
+						<line number="66" hits="0"/>
+						<line number="67" hits="0"/>
+						<line number="69" hits="0"/>
+						<line number="71" hits="0"/>
+						<line number="72" hits="0"/>
+						<line number="73" hits="0"/>
+						<line number="74" hits="0"/>
+						<line number="75" hits="0"/>
+						<line number="76" hits="0"/>
+						<line number="77" hits="0"/>
+						<line number="78" hits="0"/>
+						<line number="79" hits="0"/>
+						<line number="81" hits="0"/>
+						<line number="84" hits="0"/>
+						<line number="86" hits="0"/>
+					</lines>
+				</class>
+				<class name="test_executor.py" filename="test_executor.py" complexity="0" line-rate="0.5" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="3" hits="1"/>
+						<line number="4" hits="1"/>
+						<line number="6" hits="1"/>
+						<line number="9" hits="1"/>
+						<line number="39" hits="1"/>
+						<line number="41" hits="0"/>
+						<line number="53" hits="0"/>
+						<line number="54" hits="0"/>
+						<line number="57" hits="1"/>
+						<line number="91" hits="1"/>
+						<line number="93" hits="0"/>
+						<line number="105" hits="0"/>
+						<line number="106" hits="0"/>
+						<line number="109" hits="1"/>
+						<line number="121" hits="1"/>
+						<line number="123" hits="0"/>
+						<line number="135" hits="0"/>
+						<line number="138" hits="0"/>
+					</lines>
+				</class>
+				<class name="test_mysql.py" filename="test_mysql.py" complexity="0" line-rate="0.2727" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="4" hits="1"/>
+						<line number="8" hits="1"/>
+						<line number="10" hits="0"/>
+						<line number="13" hits="1"/>
+						<line number="15" hits="0"/>
+						<line number="16" hits="0"/>
+						<line number="17" hits="0"/>
+						<line number="18" hits="0"/>
+						<line number="21" hits="1"/>
+						<line number="23" hits="0"/>
+						<line number="26" hits="1"/>
+						<line number="28" hits="0"/>
+						<line number="29" hits="0"/>
+						<line number="30" hits="0"/>
+						<line number="31" hits="0"/>
+						<line number="33" hits="0"/>
+						<line number="34" hits="0"/>
+						<line number="35" hits="0"/>
+						<line number="36" hits="0"/>
+						<line number="39" hits="1"/>
+						<line number="41" hits="0"/>
+						<line number="42" hits="0"/>
+					</lines>
+				</class>
+				<class name="test_mysqlnoproc.py" filename="test_mysqlnoproc.py" complexity="0" line-rate="0.5556" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="1" hits="1"/>
+						<line number="2" hits="1"/>
+						<line number="4" hits="1"/>
+						<line number="5" hits="1"/>
+						<line number="8" hits="1"/>
+						<line number="10" hits="0"/>
+						<line number="11" hits="0"/>
+						<line number="12" hits="0"/>
+						<line number="13" hits="0"/>
+					</lines>
+				</class>
+			</classes>
+		</package>
+		<package name="factories" line-rate="0.1977" branch-rate="0" complexity="0">
+			<classes>
+				<class name="__init__.py" filename="factories/__init__.py" complexity="0" line-rate="0" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="2" hits="0"/>
+						<line number="3" hits="0"/>
+						<line number="4" hits="0"/>
+						<line number="6" hits="0"/>
+					</lines>
+				</class>
+				<class name="client.py" filename="factories/client.py" complexity="0" line-rate="0.2333" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="18" hits="0"/>
+						<line number="19" hits="0"/>
+						<line number="21" hits="0"/>
+						<line number="22" hits="0"/>
+						<line number="24" hits="0"/>
+						<line number="25" hits="0"/>
+						<line number="26" hits="0"/>
+						<line number="29" hits="0"/>
+						<line number="58" hits="1"/>
+						<line number="59" hits="1"/>
+						<line number="75" hits="1"/>
+						<line number="76" hits="1"/>
+						<line number="79" hits="1"/>
+						<line number="80" hits="0"/>
+						<line number="82" hits="1"/>
+						<line number="84" hits="0"/>
+						<line number="85" hits="0"/>
+						<line number="86" hits="0"/>
+						<line number="88" hits="0"/>
+						<line number="93" hits="0"/>
+						<line number="94" hits="0"/>
+						<line number="96" hits="0"/>
+						<line number="98" hits="0"/>
+						<line number="100" hits="0"/>
+						<line number="105" hits="0"/>
+						<line number="107" hits="0"/>
+						<line number="110" hits="0"/>
+						<line number="111" hits="0"/>
+						<line number="112" hits="0"/>
+						<line number="114" hits="1"/>
+					</lines>
+				</class>
+				<class name="noprocess.py" filename="factories/noprocess.py" complexity="0" line-rate="0.3684" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="18" hits="0"/>
+						<line number="20" hits="0"/>
+						<line number="21" hits="0"/>
+						<line number="23" hits="0"/>
+						<line number="24" hits="0"/>
+						<line number="26" hits="0"/>
+						<line number="27" hits="0"/>
+						<line number="28" hits="0"/>
+						<line number="31" hits="0"/>
+						<line number="42" hits="1"/>
+						<line number="43" hits="1"/>
+						<line number="54" hits="1"/>
+						<line number="55" hits="1"/>
+						<line number="56" hits="1"/>
+						<line number="57" hits="0"/>
+						<line number="59" hits="1"/>
+						<line number="64" hits="1"/>
+						<line number="65" hits="0"/>
+						<line number="67" hits="0"/>
+					</lines>
+				</class>
+				<class name="process.py" filename="factories/process.py" complexity="0" line-rate="0.09091" branch-rate="0">
+					<methods/>
+					<lines>
+						<line number="18" hits="0"/>
+						<line number="20" hits="0"/>
+						<line number="21" hits="0"/>
+						<line number="23" hits="0"/>
+						<line number="24" hits="0"/>
+						<line number="25" hits="0"/>
+						<line number="27" hits="0"/>
+						<line number="28" hits="0"/>
+						<line number="29" hits="0"/>
+						<line number="32" hits="0"/>
+						<line number="63" hits="1"/>
+						<line number="64" hits="1"/>
+						<line number="83" hits="0"/>
+						<line number="84" hits="0"/>
+						<line number="85" hits="0"/>
+						<line number="86" hits="0"/>
+						<line number="87" hits="0"/>
+						<line number="88" hits="0"/>
+						<line number="89" hits="0"/>
+						<line number="90" hits="0"/>
+						<line number="92" hits="0"/>
+						<line number="94" hits="0"/>
+						<line number="95" hits="0"/>
+						<line number="103" hits="0"/>
+						<line number="104" hits="0"/>
+						<line number="105" hits="0"/>
+						<line number="111" hits="0"/>
+						<line number="112" hits="0"/>
+						<line number="117" hits="0"/>
+						<line number="119" hits="0"/>
+						<line number="131" hits="0"/>
+						<line number="132" hits="0"/>
+						<line number="134" hits="1"/>
+					</lines>
+				</class>
+			</classes>
+		</package>
+	</packages>
+</coverage>


Test patch:
diff --git a/.github/workflows/tests-mariadb.yml b/.github/workflows/tests-mariadb.yml
index b1b696b4..6e24f133 100644
--- a/.github/workflows/tests-mariadb.yml
+++ b/.github/workflows/tests-mariadb.yml
@@ -20,10 +20,23 @@ jobs:
     env:
       OS: ubuntu-latest
       PYTHON: ${{ matrix.python-version }}
-    # Service containers to run with `container-job`
+    services:
+      mysql:
+        image: mariadb
+        env:
+          MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
+          MARIADB_DATABASE: tests
+        ports:
+          - 3333:3306
+        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
 
     steps:
     - uses: actions/checkout@v2
+    - name: Verify MariaDB connection
+      run: |
+        while ! mysqladmin ping -h"127.0.0.1" -P"3333" --silent; do
+          sleep 1
+        done
     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v2
       with:
@@ -38,10 +51,13 @@ jobs:
         pip install -r requirements-test.txt
     - name: Run test
       run: |
-        pytest --mysql-user=$USER -n 0 --cov-report=xml
+        pytest --mysql-user=$USER -n 0 -k "not mysqlnoproc" --cov-report=xml
     - name: Run xdist test
       run: |
-        pytest --mysql-user=$USER -n 1 --cov-report=xml:coverage-xdist.xml
+        pytest --mysql-user=$USER -n 1 -k "not mysqlnoproc" --cov-report=xml:coverage-xdist.xml
+    - name: Run noproc test
+      run: |
+        pytest -n 0 -k mysqlnoproc --cov-report=xml:coverage-noproc.xml --mysql-host="127.0.0.1" --mysql-port=3333
     - name: Upload coverage to Codecov
       uses: codecov/codecov-action@v1
       with:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2e31d1f1..286df45d 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -21,9 +21,23 @@ jobs:
       OS: ubuntu-latest
       PYTHON: ${{ matrix.python-version }}
     # Service containers to run with `container-job`
+    services:
+      mysql:
+        image: mysql
+        env:
+          MYSQL_ALLOW_EMPTY_PASSWORD: yes
+          MYSQL_DATABASE: tests
+        ports:
+          - 3333:3306
+        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
 
     steps:
     - uses: actions/checkout@v2
+    - name: Verify MySQL connection
+      run: |
+        while ! mysqladmin ping -h"127.0.0.1" -P"3333" --silent; do
+          sleep 1
+        done
     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v2
       with:
@@ -38,14 +52,17 @@ jobs:
         pip install -r requirements-test.txt
     - name: Run test
       run: |
-        pytest -n 0 --cov-report=xml
+        pytest -n 0 -k "not mysqlnoproc" --cov-report=xml
     - name: Run xdist test
       run: |
-        pytest -n 1 --cov-report=xml:coverage-xdist.xml
+        pytest -n 1 -k "not mysqlnoproc" --cov-report=xml:coverage-xdist.xml
+    - name: Run noproc test
+      run: |
+        pytest -n 0 -k mysqlnoproc --cov-report=xml:coverage-noproc.xml --mysql-host="127.0.0.1" --mysql-port=3333
     - name: Upload coverage to Codecov
       uses: codecov/codecov-action@v1
       with:
-        files: ./coverage.xml, ./coverage-xdist.xml
+        files: ./coverage.xml, ./coverage-xdist.xml, ./coverage-noproc.xml
         flags: linux,mysql
         env_vars: OS, PYTHON
         fail_ci_if_error: true
diff --git a/src/pytest_mysql/config.py b/src/pytest_mysql/config.py
new file mode 100644
index 00000000..f9a3595a
--- /dev/null
+++ b/src/pytest_mysql/config.py
@@ -0,0 +1,23 @@
+def get_config(request):
+    """Return a dictionary with config options."""
+    config = {}
+    options = [
+        "mysqld",
+        "mysqld_safe",
+        "admin",
+        "host",
+        "port",
+        "user",
+        "passwd",
+        "dbname",
+        "params",
+        "logsdir",
+        "install_db",
+    ]
+    for option in options:
+        option_name = "mysql_" + option
+        conf = request.config.getoption(option_name) or request.config.getini(
+            option_name
+        )
+        config[option] = conf
+    return config
diff --git a/src/pytest_mysql/executor.py b/src/pytest_mysql/executor.py
index 7819b7b3..4170861c 100644
--- a/src/pytest_mysql/executor.py
+++ b/src/pytest_mysql/executor.py
@@ -61,7 +61,7 @@ def __init__(
         self.base_directory = base_directory
         self.datadir = self.base_directory.mkdir(f"mysqldata_{port}")
         self.pidfile = self.base_directory.join(f"mysql-server.{port}.pid")
-        self.unixsocket = self.base_directory.join(f"mysql.{port}.sock")
+        self.unixsocket = str(self.base_directory.join(f"mysql.{port}.sock"))
         self.logfile_path = logfile_path
         self.user = user
         self._initialised = False
diff --git a/src/pytest_mysql/executor_noop.py b/src/pytest_mysql/executor_noop.py
new file mode 100644
index 00000000..4dafa304
--- /dev/null
+++ b/src/pytest_mysql/executor_noop.py
@@ -0,0 +1,23 @@
+class NoopMySQLExecutor:
+    def __init__(
+        self,
+        user,
+        host,
+        port,
+    ):
+        self.user = user
+        self.host = host
+        self.port = port
+        self.unixsocket = None
+
+    def running(self):
+        """Check if process is running."""
+        return True
+
+    def __enter__(self):
+        """Dummy enter method."""
+        pass
+
+    def __exit__(self, *args, **kwargs):
+        """Dummy exit method."""
+        pass
diff --git a/src/pytest_mysql/factories/__init__.py b/src/pytest_mysql/factories/__init__.py
index 36ea8d70..19bfa5e9 100644
--- a/src/pytest_mysql/factories/__init__.py
+++ b/src/pytest_mysql/factories/__init__.py
@@ -1,5 +1,6 @@
 """Factories module."""
 from pytest_mysql.factories.client import mysql
 from pytest_mysql.factories.process import mysql_proc
+from pytest_mysql.factories.noprocess import mysql_noproc
 
-__all__ = ("mysql", "mysql_proc")
+__all__ = ("mysql", "mysql_proc", "mysql_noproc")
diff --git a/src/pytest_mysql/factories/client.py b/src/pytest_mysql/factories/client.py
index 450ca6b1..6da156eb 100644
--- a/src/pytest_mysql/factories/client.py
+++ b/src/pytest_mysql/factories/client.py
@@ -16,11 +16,14 @@
 # You should have received a copy of the GNU Lesser General Public License
 # along with pytest-mysql.  If not, see <http://www.gnu.org/licenses/>.
 """Client fixture factory for MySQL database."""
+from typing import Union
 
 import pytest
 import MySQLdb
 
-from pytest_mysql.factories.process import get_config
+from pytest_mysql.config import get_config
+from pytest_mysql.executor import MySQLExecutor
+from pytest_mysql.executor_noop import NoopMySQLExecutor
 
 
 def mysql(
@@ -70,21 +73,27 @@ def mysql_fixture(request) -> MySQLdb.Connection:
         :returns: connection to database
         """
         config = get_config(request)
-        process = request.getfixturevalue(process_fixture_name)
+        process: Union[
+            NoopMySQLExecutor, MySQLExecutor
+        ] = request.getfixturevalue(process_fixture_name)
         if not process.running():
             process.start()
 
-        mysql_host = process.host
         mysql_user = "root"
         mysql_passwd = passwd or config["passwd"]
         mysql_db = dbname or config["dbname"]
 
-        mysql_conn: MySQLdb.Connection = MySQLdb.connect(
-            host=mysql_host,
-            unix_socket=process.unixsocket.strpath,
-            user=mysql_user,
-            passwd=mysql_passwd,
-        )
+        connection_kwargs = {
+            "host": process.host,
+            "user": mysql_user,
+            "passwd": mysql_passwd,
+        }
+        if process.unixsocket:
+            connection_kwargs["unix_socket"] = process.unixsocket
+        else:
+            connection_kwargs["port"] = process.port
+
+        mysql_conn: MySQLdb.Connection = MySQLdb.connect(**connection_kwargs)
 
         mysql_conn.query(
             f"CREATE DATABASE {mysql_db} "
diff --git a/src/pytest_mysql/factories/noprocess.py b/src/pytest_mysql/factories/noprocess.py
new file mode 100644
index 00000000..0ac539af
--- /dev/null
+++ b/src/pytest_mysql/factories/noprocess.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2013 by Clearcode <http://clearcode.cc>
+# and associates (see AUTHORS).
+
+# This file is part of pytest-mysql.
+
+# pytest-mysql is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# pytest-mysql is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with pytest-mysql.  If not, see <http://www.gnu.org/licenses/>.
+"""Process fixture factory for MySQL database."""
+
+import os
+from warnings import warn
+
+import pytest
+from _pytest.fixtures import FixtureRequest
+
+from pytest_mysql.config import get_config
+from pytest_mysql.executor_noop import NoopMySQLExecutor
+from pytest_mysql.port import get_port
+
+
+def mysql_noproc(host=None, port=None):
+    """
+    Process fixture factory for MySQL server.
+
+    :param str host: hostname
+    :param int port:
+    :rtype: func
+    :returns: function which makes a redis process
+
+    """
+
+    @pytest.fixture(scope="session")
+    def mysql_noproc_fixture(request: FixtureRequest):
+        """
+        Process fixture for MySQL server.
+
+        #. Get config.
+
+        :param request: fixture request object
+        :rtype: pytest_dbfixtures.executors.TCPExecutor
+        :returns: tcp executor
+
+        """
+        config = get_config(request)
+        mysql_port = int(port or config["port"] or 3306)
+        mysql_host = host or config["host"]
+
+        mysql_executor = NoopMySQLExecutor(
+            user=config["user"],
+            host=mysql_host,
+            port=mysql_port,
+        )
+        with mysql_executor:
+            yield mysql_executor
+
+    return mysql_noproc_fixture
diff --git a/src/pytest_mysql/factories/process.py b/src/pytest_mysql/factories/process.py
index b3f41622..4a5f9eb9 100644
--- a/src/pytest_mysql/factories/process.py
+++ b/src/pytest_mysql/factories/process.py
@@ -24,35 +24,11 @@
 from _pytest.fixtures import FixtureRequest
 from _pytest.tmpdir import TempdirFactory
 
+from pytest_mysql.config import get_config
 from pytest_mysql.executor import MySQLExecutor
 from pytest_mysql.port import get_port
 
 
-def get_config(request):
-    """Return a dictionary with config options."""
-    config = {}
-    options = [
-        "mysqld",
-        "mysqld_safe",
-        "admin",
-        "host",
-        "port",
-        "user",
-        "passwd",
-        "dbname",
-        "params",
-        "logsdir",
-        "install_db",
-    ]
-    for option in options:
-        option_name = "mysql_" + option
-        conf = request.config.getoption(option_name) or request.config.getini(
-            option_name
-        )
-        config[option] = conf
-    return config
-
-
 def mysql_proc(
     mysqld_exec=None,
     admin_executable=None,
diff --git a/src/pytest_mysql/plugin.py b/src/pytest_mysql/plugin.py
index 2b9522eb..f19921d7 100644
--- a/src/pytest_mysql/plugin.py
+++ b/src/pytest_mysql/plugin.py
@@ -142,4 +142,5 @@ def pytest_addoption(parser):
 
 
 mysql_proc = factories.mysql_proc()
+mysql_noproc = factories.mysql_noproc()
 mysql = factories.mysql("mysql_proc")
diff --git a/tests/test_mysqlnoproc.py b/tests/test_mysqlnoproc.py
new file mode 100644
index 00000000..1e411e27
--- /dev/null
+++ b/tests/test_mysqlnoproc.py
@@ -0,0 +1,13 @@
+from pytest_mysql import factories
+from tests.test_mysql import QUERY
+
+mysql_noproc2 = factories.mysql_noproc()
+mysqlnoproc_client = factories.mysql("mysql_noproc2")
+
+
+def test_mysql_noproc(mysqlnoproc_client):
+    """Check if noproc fixture connects to the running mysql instance."""
+    cursor = mysqlnoproc_client.cursor()
+    cursor.execute(QUERY)
+    mysqlnoproc_client.commit()
+    cursor.close()