diff --git a/tests/components/modbus/conftest.py b/tests/components/modbus/conftest.py
index 66f4d542525dc45fdcf0686d3660a131c3b796d6..36495acc9c5d11db1a95f92be4e8be27aa37b30a 100644
--- a/tests/components/modbus/conftest.py
+++ b/tests/components/modbus/conftest.py
@@ -1,5 +1,4 @@
 """The tests for the Modbus sensor component."""
-from datetime import timedelta
 import logging
 from unittest import mock
 
@@ -40,20 +39,17 @@ class ReadResult:
         self.bits = register_words
 
 
-async def run_base_test(
+async def setup_base_test(
     sensor_name,
     hass,
     use_mock_hub,
     data_array,
-    register_type,
     entity_domain,
-    register_words,
-    expected,
+    scan_interval,
 ):
-    """Run test for given config."""
+    """Run setup device for given config."""
 
     # Full sensor configuration
-    scan_interval = 5
     config = {
         entity_domain: {
             CONF_PLATFORM: "modbus",
@@ -62,6 +58,28 @@ async def run_base_test(
         }
     }
 
+    # Initialize sensor
+    now = dt_util.utcnow()
+    with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
+        assert await async_setup_component(hass, entity_domain, config)
+        await hass.async_block_till_done()
+
+    entity_id = f"{entity_domain}.{sensor_name}"
+    device = hass.states.get(entity_id)
+    return entity_id, now, device
+
+
+async def run_base_read_test(
+    entity_id,
+    hass,
+    use_mock_hub,
+    register_type,
+    register_words,
+    expected,
+    now,
+):
+    """Run test for given config."""
+
     # Setup inputs for the sensor
     read_result = ReadResult(register_words)
     if register_type == CALL_TYPE_COIL:
@@ -73,14 +91,11 @@ async def run_base_test(
     else:  # CALL_TYPE_REGISTER_HOLDING
         use_mock_hub.read_holding_registers.return_value = read_result
 
-    # Initialize sensor
-    now = dt_util.utcnow()
-    with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
-        assert await async_setup_component(hass, entity_domain, config)
-        await hass.async_block_till_done()
-
     # Trigger update call with time_changed event
-    now += timedelta(seconds=scan_interval + 1)
     with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
         async_fire_time_changed(hass, now)
         await hass.async_block_till_done()
+
+    # Check state
+    state = hass.states.get(entity_id).state
+    assert state == expected
diff --git a/tests/components/modbus/test_modbus_binary_sensor.py b/tests/components/modbus/test_modbus_binary_sensor.py
index ff64ad8723ad59c2b71510e760df066635bfa0d0..63513872e79fe5fe6033b11f3ecba385791a0518 100644
--- a/tests/components/modbus/test_modbus_binary_sensor.py
+++ b/tests/components/modbus/test_modbus_binary_sensor.py
@@ -1,4 +1,5 @@
 """The tests for the Modbus sensor component."""
+from datetime import timedelta
 import logging
 
 from homeassistant.components.binary_sensor import DOMAIN as SENSOR_DOMAIN
@@ -11,7 +12,7 @@ from homeassistant.components.modbus.const import (
 )
 from homeassistant.const import CONF_NAME, STATE_OFF, STATE_ON
 
-from .conftest import run_base_test
+from .conftest import run_base_read_test, setup_base_test
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -19,28 +20,29 @@ _LOGGER = logging.getLogger(__name__)
 async def run_sensor_test(hass, use_mock_hub, register_config, value, expected):
     """Run test for given config."""
     sensor_name = "modbus_test_binary_sensor"
-    entity_domain = SENSOR_DOMAIN
-    data_array = {
-        CONF_INPUTS: [
-            dict(**{CONF_NAME: sensor_name, CONF_ADDRESS: 1234}, **register_config)
-        ]
-    }
-    await run_base_test(
+    scan_interval = 5
+    entity_id, now, device = await setup_base_test(
         sensor_name,
         hass,
         use_mock_hub,
-        data_array,
+        {
+            CONF_INPUTS: [
+                dict(**{CONF_NAME: sensor_name, CONF_ADDRESS: 1234}, **register_config)
+            ]
+        },
+        SENSOR_DOMAIN,
+        scan_interval,
+    )
+    await run_base_read_test(
+        entity_id,
+        hass,
+        use_mock_hub,
         register_config.get(CONF_INPUT_TYPE),
-        entity_domain,
         value,
         expected,
+        now + timedelta(seconds=scan_interval + 1),
     )
 
-    # Check state
-    entity_id = f"{entity_domain}.{sensor_name}"
-    state = hass.states.get(entity_id).state
-    assert state == expected
-
 
 async def test_coil_true(hass, mock_hub):
     """Test conversion of single word register."""
diff --git a/tests/components/modbus/test_modbus_sensor.py b/tests/components/modbus/test_modbus_sensor.py
index 5ade2f197ddb6d5d6377ea4e0de8bfdad76dcbb7..59d845ef053bf01464b2874f11c4f0af44744b4e 100644
--- a/tests/components/modbus/test_modbus_sensor.py
+++ b/tests/components/modbus/test_modbus_sensor.py
@@ -1,4 +1,5 @@
 """The tests for the Modbus sensor component."""
+from datetime import timedelta
 import logging
 
 from homeassistant.components.modbus.const import (
@@ -21,7 +22,7 @@ from homeassistant.components.modbus.const import (
 from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
 from homeassistant.const import CONF_NAME
 
-from .conftest import run_base_test
+from .conftest import run_base_read_test, setup_base_test
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -31,363 +32,344 @@ async def run_sensor_test(
 ):
     """Run test for sensor."""
     sensor_name = "modbus_test_sensor"
-    entity_domain = SENSOR_DOMAIN
-    data_array = {
-        CONF_REGISTERS: [
-            dict(**{CONF_NAME: sensor_name, CONF_REGISTER: 1234}, **register_config)
-        ]
-    }
-
-    await run_base_test(
+    scan_interval = 5
+    entity_id, now, device = await setup_base_test(
         sensor_name,
         hass,
         use_mock_hub,
-        data_array,
+        {
+            CONF_REGISTERS: [
+                dict(**{CONF_NAME: sensor_name, CONF_REGISTER: 1234}, **register_config)
+            ]
+        },
+        SENSOR_DOMAIN,
+        scan_interval,
+    )
+    await run_base_read_test(
+        entity_id,
+        hass,
+        use_mock_hub,
         register_config.get(CONF_REGISTER_TYPE),
-        entity_domain,
         register_words,
         expected,
+        now + timedelta(seconds=scan_interval + 1),
     )
 
-    # Check state
-    entity_id = f"{entity_domain}.{sensor_name}"
-    state = hass.states.get(entity_id).state
-    assert state == expected
-
 
 async def test_simple_word_register(hass, mock_hub):
     """Test conversion of single word register."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0],
-        expected="0",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0],
+        "0",
     )
 
 
 async def test_optional_conf_keys(hass, mock_hub):
     """Test handling of optional configuration keys."""
-    register_config = {}
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x8000],
-        expected="-32768",
+        {},
+        [0x8000],
+        "-32768",
     )
 
 
 async def test_offset(hass, mock_hub):
     """Test offset calculation."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 13,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[7],
-        expected="20",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 13,
+            CONF_PRECISION: 0,
+        },
+        [7],
+        "20",
     )
 
 
 async def test_scale_and_offset(hass, mock_hub):
     """Test handling of scale and offset."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 3,
-        CONF_OFFSET: 13,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[7],
-        expected="34",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 3,
+            CONF_OFFSET: 13,
+            CONF_PRECISION: 0,
+        },
+        [7],
+        "34",
     )
 
 
 async def test_ints_can_have_precision(hass, mock_hub):
     """Test precision can be specified event if using integer values only."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 3,
-        CONF_OFFSET: 13,
-        CONF_PRECISION: 4,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[7],
-        expected="34.0000",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 3,
+            CONF_OFFSET: 13,
+            CONF_PRECISION: 4,
+        },
+        [7],
+        "34.0000",
     )
 
 
 async def test_floats_get_rounded_correctly(hass, mock_hub):
     """Test that floating point values get rounded correctly."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 1.5,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[1],
-        expected="2",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 1.5,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [1],
+        "2",
     )
 
 
 async def test_parameters_as_strings(hass, mock_hub):
     """Test that scale, offset and precision can be given as strings."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: "1.5",
-        CONF_OFFSET: "5",
-        CONF_PRECISION: "1",
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[9],
-        expected="18.5",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: "1.5",
+            CONF_OFFSET: "5",
+            CONF_PRECISION: "1",
+        },
+        [9],
+        "18.5",
     )
 
 
 async def test_floating_point_scale(hass, mock_hub):
     """Test use of floating point scale."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 2.4,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 2,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[1],
-        expected="2.40",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 2.4,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 2,
+        },
+        [1],
+        "2.40",
     )
 
 
 async def test_floating_point_offset(hass, mock_hub):
     """Test use of floating point scale."""
-    register_config = {
-        CONF_COUNT: 1,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: -10.3,
-        CONF_PRECISION: 1,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[2],
-        expected="-8.3",
+        {
+            CONF_COUNT: 1,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: -10.3,
+            CONF_PRECISION: 1,
+        },
+        [2],
+        "-8.3",
     )
 
 
 async def test_signed_two_word_register(hass, mock_hub):
     """Test reading of signed register with two words."""
-    register_config = {
-        CONF_COUNT: 2,
-        CONF_DATA_TYPE: DATA_TYPE_INT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x89AB, 0xCDEF],
-        expected="-1985229329",
+        {
+            CONF_COUNT: 2,
+            CONF_DATA_TYPE: DATA_TYPE_INT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0x89AB, 0xCDEF],
+        "-1985229329",
     )
 
 
 async def test_unsigned_two_word_register(hass, mock_hub):
     """Test reading of unsigned register with two words."""
-    register_config = {
-        CONF_COUNT: 2,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x89AB, 0xCDEF],
-        expected=str(0x89ABCDEF),
+        {
+            CONF_COUNT: 2,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0x89AB, 0xCDEF],
+        str(0x89ABCDEF),
     )
 
 
 async def test_reversed(hass, mock_hub):
     """Test handling of reversed register words."""
-    register_config = {
-        CONF_COUNT: 2,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_REVERSE_ORDER: True,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x89AB, 0xCDEF],
-        expected=str(0xCDEF89AB),
+        {
+            CONF_COUNT: 2,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_REVERSE_ORDER: True,
+        },
+        [0x89AB, 0xCDEF],
+        str(0xCDEF89AB),
     )
 
 
 async def test_four_word_register(hass, mock_hub):
     """Test reading of 64-bit register."""
-    register_config = {
-        CONF_COUNT: 4,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x89AB, 0xCDEF, 0x0123, 0x4567],
-        expected="9920249030613615975",
+        {
+            CONF_COUNT: 4,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0x89AB, 0xCDEF, 0x0123, 0x4567],
+        "9920249030613615975",
     )
 
 
 async def test_four_word_register_precision_is_intact_with_int_params(hass, mock_hub):
     """Test that precision is not lost when doing integer arithmetic for 64-bit register."""
-    register_config = {
-        CONF_COUNT: 4,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 2,
-        CONF_OFFSET: 3,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x0123, 0x4567, 0x89AB, 0xCDEF],
-        expected="163971058432973793",
+        {
+            CONF_COUNT: 4,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 2,
+            CONF_OFFSET: 3,
+            CONF_PRECISION: 0,
+        },
+        [0x0123, 0x4567, 0x89AB, 0xCDEF],
+        "163971058432973793",
     )
 
 
 async def test_four_word_register_precision_is_lost_with_float_params(hass, mock_hub):
     """Test that precision is affected when floating point conversion is done."""
-    register_config = {
-        CONF_COUNT: 4,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 2.0,
-        CONF_OFFSET: 3.0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x0123, 0x4567, 0x89AB, 0xCDEF],
-        expected="163971058432973792",
+        {
+            CONF_COUNT: 4,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 2.0,
+            CONF_OFFSET: 3.0,
+            CONF_PRECISION: 0,
+        },
+        [0x0123, 0x4567, 0x89AB, 0xCDEF],
+        "163971058432973792",
     )
 
 
 async def test_two_word_input_register(hass, mock_hub):
     """Test reaging of input register."""
-    register_config = {
-        CONF_COUNT: 2,
-        CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_INPUT,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x89AB, 0xCDEF],
-        expected=str(0x89ABCDEF),
+        {
+            CONF_COUNT: 2,
+            CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_INPUT,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0x89AB, 0xCDEF],
+        str(0x89ABCDEF),
     )
 
 
 async def test_two_word_holding_register(hass, mock_hub):
     """Test reaging of holding register."""
-    register_config = {
-        CONF_COUNT: 2,
-        CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
-        CONF_DATA_TYPE: DATA_TYPE_UINT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x89AB, 0xCDEF],
-        expected=str(0x89ABCDEF),
+        {
+            CONF_COUNT: 2,
+            CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
+            CONF_DATA_TYPE: DATA_TYPE_UINT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0x89AB, 0xCDEF],
+        str(0x89ABCDEF),
     )
 
 
 async def test_float_data_type(hass, mock_hub):
     """Test floating point register data type."""
-    register_config = {
-        CONF_COUNT: 2,
-        CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
-        CONF_DATA_TYPE: DATA_TYPE_FLOAT,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 5,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[16286, 1617],
-        expected="1.23457",
+        {
+            CONF_COUNT: 2,
+            CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
+            CONF_DATA_TYPE: DATA_TYPE_FLOAT,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 5,
+        },
+        [16286, 1617],
+        "1.23457",
     )
 
 
 async def test_string_data_type(hass, mock_hub):
     """Test byte string register data type."""
-    register_config = {
-        CONF_COUNT: 8,
-        CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
-        CONF_DATA_TYPE: DATA_TYPE_STRING,
-        CONF_SCALE: 1,
-        CONF_OFFSET: 0,
-        CONF_PRECISION: 0,
-    }
     await run_sensor_test(
         hass,
         mock_hub,
-        register_config,
-        register_words=[0x3037, 0x2D30, 0x352D, 0x3230, 0x3230, 0x2031, 0x343A, 0x3335],
-        expected="07-05-2020 14:35",
+        {
+            CONF_COUNT: 8,
+            CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
+            CONF_DATA_TYPE: DATA_TYPE_STRING,
+            CONF_SCALE: 1,
+            CONF_OFFSET: 0,
+            CONF_PRECISION: 0,
+        },
+        [0x3037, 0x2D30, 0x352D, 0x3230, 0x3230, 0x2031, 0x343A, 0x3335],
+        "07-05-2020 14:35",
     )
diff --git a/tests/components/modbus/test_modbus_switch.py b/tests/components/modbus/test_modbus_switch.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac1d8bd696308ada38b5358303e528a858ae212f
--- /dev/null
+++ b/tests/components/modbus/test_modbus_switch.py
@@ -0,0 +1,59 @@
+"""The tests for the Modbus switch component."""
+from datetime import timedelta
+import logging
+
+from homeassistant.components.modbus.const import CALL_TYPE_COIL, CONF_COILS
+from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
+from homeassistant.const import CONF_NAME, CONF_SLAVE
+
+from .conftest import run_base_read_test, setup_base_test
+
+_LOGGER = logging.getLogger(__name__)
+
+
+async def run_sensor_test(hass, use_mock_hub, value, expected):
+    """Run test for given config."""
+    switch_name = "modbus_test_switch"
+    scan_interval = 5
+    entity_id, now, device = await setup_base_test(
+        switch_name,
+        hass,
+        use_mock_hub,
+        {
+            CONF_COILS: [
+                {CONF_NAME: switch_name, CALL_TYPE_COIL: 1234, CONF_SLAVE: 1},
+            ]
+        },
+        SWITCH_DOMAIN,
+        scan_interval,
+    )
+
+    await run_base_read_test(
+        entity_id,
+        hass,
+        use_mock_hub,
+        CALL_TYPE_COIL,
+        value,
+        expected,
+        now + timedelta(seconds=scan_interval + 1),
+    )
+
+
+async def test_read_coil_false(hass, mock_hub):
+    """Test reading of switch coil."""
+    await run_sensor_test(
+        hass,
+        mock_hub,
+        [0x00],
+        expected="off",
+    )
+
+
+async def test_read_coil_true(hass, mock_hub):
+    """Test reading of switch coil."""
+    await run_sensor_test(
+        hass,
+        mock_hub,
+        [0xFF],
+        expected="on",
+    )