diff --git a/tests/test_common_cells.hpp b/tests/test_common_cells.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4641c879950fb6a5249cc25f38c3e6006df69ea
--- /dev/null
+++ b/tests/test_common_cells.hpp
@@ -0,0 +1,112 @@
+#include <cell.hpp>
+#include <parameter_list.hpp>
+
+namespace nest {
+namespace mc {
+
+/*
+ * Create cell with just a soma:
+ *
+ * Soma:
+ *    diameter: 18.8 µm
+ *    mechanisms: membrane, HH
+ *    memrane resistance: 123 Ω·cm
+ *
+ * Stimuli:
+ *    soma centre, t=[10 ms, 110 ms), 0.1 nA
+ */
+
+inline cell make_cell_soma_only() {
+    cell c;
+
+    auto soma = c.add_soma(18.8/2.0);
+    soma->mechanism("membrane").set("r_L", 123);
+    soma->add_mechanism(hh_parameters());
+
+    c.add_stimulus({0,0.5}, {10., 100., 0.1});
+
+    return c;
+}
+
+/*
+ * Create cell with a soma and unbranched dendrite:
+ *
+ * Soma:
+ *    mechanisms: HH
+ *    diameter: 12.6157 µm
+ *
+ * Dendrite:
+ *    mechanisms: none
+ *    diameter: 1 µm
+ *    length: 200 µm
+ *    membrane resistance: 100 Ω·cm
+ *    compartments: 4
+ *
+ * Stimulus:
+ *    end of dendrite, t=[5 ms, 85 ms), 0.3 nA
+ */
+
+inline cell make_cell_ball_and_stick() {
+    cell c;
+
+    auto soma = c.add_soma(12.6157/2.0);
+    soma->add_mechanism(hh_parameters());
+
+    auto dendrite = c.add_cable(0, segmentKind::dendrite, 1.0/2, 1.0/2, 200.0);
+    dendrite->add_mechanism(pas_parameters());
+    dendrite->mechanism("membrane").set("r_L", 100);
+    dendrite->set_compartments(4);
+
+    c.add_stimulus({1,1}, {5., 80., 0.3});
+
+    return c;
+}
+
+/*
+ * Create cell with a soma and three-segment dendrite with single branch point:
+ *
+ * O----======
+ *
+ * Soma:
+ *    mechanisms: HH
+ *    diameter: 12.6157 µm
+ *
+ * Dendrites:
+ *    mechanisms: membrane
+ *    diameter: 1 µm
+ *    length: 100 µm
+ *    membrane resistance: 100 Ω·cm
+ *    compartments: 4
+ *
+ * Stimulus:
+ *    end of first terminal branch, t=[5 ms, 85 ms), 0.45 nA
+ *    end of second terminal branch, t=[40 ms, 50 ms), -0.2 nA
+ */
+
+inline cell make_cell_ball_and_3sticks() {
+    cell c;
+
+    auto soma = c.add_soma(12.6157/2.0);
+    soma->add_mechanism(hh_parameters());
+
+    // add dendrite of length 200 um and diameter 1 um with passive channel
+    c.add_cable(0, segmentKind::dendrite, 0.5, 0.5, 100);
+    c.add_cable(1, segmentKind::dendrite, 0.5, 0.5, 100);
+    c.add_cable(1, segmentKind::dendrite, 0.5, 0.5, 100);
+
+    for (auto& seg: c.segments()) {
+        if (seg->is_dendrite()) {
+            seg->add_mechanism(pas_parameters());
+            seg->mechanism("membrane").set("r_L", 100);
+            seg->set_compartments(4);
+        }
+    }
+
+    c.add_stimulus({2,1}, {5.,  80., 0.45});
+    c.add_stimulus({3,1}, {40., 10.,-0.2});
+
+    return c;
+}
+
+} // namespace mc
+} // namespace nest
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 6b34d70125bb4d9792f8abb6b68daf411dfe78d8..1c286863c3e92a9c8f2a11eba8679f66094b3c72 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -18,6 +18,7 @@ set(TEST_SOURCES
     test_either.cpp
     test_event_queue.cpp
     test_fvm.cpp
+    test_fvm_multi.cpp
     test_cell_group.cpp
     test_lexcmp.cpp
     test_mask_stream.cpp
diff --git a/tests/unit/test_cell_group.cpp b/tests/unit/test_cell_group.cpp
index 3aed222029f4535a85d9713849cff184a3684531..99b46e564d66edc03643fba738dcd134ef9ac90c 100644
--- a/tests/unit/test_cell_group.cpp
+++ b/tests/unit/test_cell_group.cpp
@@ -4,24 +4,15 @@
 #include <fvm_cell.hpp>
 #include <cell_group.hpp>
 
+#include "../test_common_cells.hpp"
+
 nest::mc::cell make_cell() {
     using namespace nest::mc;
 
-    nest::mc::cell cell;
-
-    // Soma with diameter 12.6157 um and HH channel
-    auto soma = cell.add_soma(12.6157/2.0);
-    soma->add_mechanism(hh_parameters());
-
-    // add dendrite of length 200 um and diameter 1 um with passive channel
-    auto dendrite = cell.add_cable(0, segmentKind::dendrite, 0.5, 0.5, 200);
-    dendrite->add_mechanism(pas_parameters());
-    dendrite->set_compartments(101);
-
-    dendrite->mechanism("membrane").set("r_L", 100);
+    nest::mc::cell cell = make_cell_ball_and_stick();
 
     cell.add_detector({0, 0}, 0);
-    cell.add_stimulus({1, 1}, {5., 80., 0.3});
+    cell.segment(1)->set_compartments(101);
 
     return cell;
 }
diff --git a/tests/unit/test_fvm.cpp b/tests/unit/test_fvm.cpp
index ae7f0b5a3c15c01fc2c952c3ca84ff860bd10294..6d067182f972a0bc65147e8345f3043230d70d9a 100644
--- a/tests/unit/test_fvm.cpp
+++ b/tests/unit/test_fvm.cpp
@@ -7,40 +7,14 @@
 #include <fvm_cell.hpp>
 #include <util/range.hpp>
 
+#include "../test_common_cells.hpp"
 #include "../test_util.hpp"
 
 TEST(fvm, cable)
 {
     using namespace nest::mc;
 
-    nest::mc::cell cell;
-
-    cell.add_soma(6e-4); // 6um in cm
-
-    // 1um radius and 4mm long, all in cm
-    cell.add_cable(0, segmentKind::dendrite, 1e-4, 1e-4, 4e-1);
-    cell.add_cable(0, segmentKind::dendrite, 1e-4, 1e-4, 4e-1);
-
-    //std::cout << cell.segment(1)->area() << " is the area\n";
-    EXPECT_EQ(cell.model().tree.num_segments(), 3u);
-
-    // add passive to all 3 segments in the cell
-    for(auto& seg :cell.segments()) {
-        seg->add_mechanism(pas_parameters());
-    }
-
-    cell.soma()->add_mechanism(hh_parameters());
-    cell.segment(2)->add_mechanism(hh_parameters());
-
-    auto& soma_hh = cell.soma()->mechanism("hh");
-
-    soma_hh.set("gnabar", 0.12);
-    soma_hh.set("gkbar", 0.036);
-    soma_hh.set("gl", 0.0003);
-    soma_hh.set("el", -54.387);
-
-    cell.segment(1)->set_compartments(4);
-    cell.segment(2)->set_compartments(4);
+    nest::mc::cell cell = make_cell_ball_and_3sticks();
 
     using fvm_cell = fvm::fvm_cell<double, cell_lid_type>;
 
@@ -53,7 +27,8 @@ TEST(fvm, cable)
 
     auto& J = fvcell.jacobian();
 
-    EXPECT_EQ(cell.num_compartments(), 9u);
+    // 1 (soma) + 3 (dendritic segments) × 4 compartments
+    EXPECT_EQ(cell.num_compartments(), 13u);
 
     // assert that the matrix has one row for each compartment
     EXPECT_EQ(J.size(), cell.num_compartments());
@@ -69,21 +44,11 @@ TEST(fvm, init)
 {
     using namespace nest::mc;
 
-    nest::mc::cell cell;
-
-    cell.add_soma(12.6157/2.0);
-    //auto& props = cell.soma()->properties;
-
-    cell.add_cable(0, segmentKind::dendrite, 0.5, 0.5, 200);
+    nest::mc::cell cell = make_cell_ball_and_stick();
 
     const auto m = cell.model();
     EXPECT_EQ(m.tree.num_segments(), 2u);
 
-    // in this context (i.e. attached to a segment on a high-level cell)
-    // a mechanism is essentially a set of parameters
-    // - the only "state" is that used to define parameters
-    cell.soma()->add_mechanism(hh_parameters());
-
     auto& soma_hh = cell.soma()->mechanism("hh");
 
     soma_hh.set("gnabar", 0.12);
@@ -112,4 +77,3 @@ TEST(fvm, init)
 
     fvcell.setup_matrix(0.01);
 }
-
diff --git a/tests/unit/test_fvm_multi.cpp b/tests/unit/test_fvm_multi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbd4de99b91198128c6b3d0f0098f38f8440984d
--- /dev/null
+++ b/tests/unit/test_fvm_multi.cpp
@@ -0,0 +1,142 @@
+#include <fstream>
+
+#include "gtest.h"
+
+#include <common_types.hpp>
+#include <cell.hpp>
+#include <fvm_multicell.hpp>
+#include <util/range.hpp>
+
+#include "../test_util.hpp"
+#include "../test_common_cells.hpp"
+
+TEST(fvm_multi, cable)
+{
+    using namespace nest::mc;
+
+    nest::mc::cell cell=make_cell_ball_and_3sticks();
+
+    using fvm_cell = fvm::fvm_multicell<double, cell_lid_type>;
+
+    std::vector<fvm_cell::target_handle> targets;
+    std::vector<fvm_cell::detector_handle> detectors;
+    std::vector<fvm_cell::probe_handle> probes;
+
+    fvm_cell fvcell;
+    fvcell.initialize(util::singleton_view(cell), detectors, targets, probes);
+
+    auto& J = fvcell.jacobian();
+
+    // 1 (soma) + 3 (dendritic segments) × 4 compartments
+    EXPECT_EQ(cell.num_compartments(), 13u);
+
+    // assert that the matrix has one row for each compartment
+    EXPECT_EQ(J.size(), cell.num_compartments());
+
+    fvcell.setup_matrix(0.02);
+
+    // assert that the number of cv areas is the same as the matrix size
+    // i.e. both should equal the number of compartments
+    EXPECT_EQ(fvcell.cv_areas().size(), J.size());
+}
+
+TEST(fvm_multi, init)
+{
+    using namespace nest::mc;
+
+    nest::mc::cell cell = make_cell_ball_and_stick();
+
+    const auto m = cell.model();
+    EXPECT_EQ(m.tree.num_segments(), 2u);
+
+    auto& soma_hh = cell.soma()->mechanism("hh");
+
+    soma_hh.set("gnabar", 0.12);
+    soma_hh.set("gkbar", 0.036);
+    soma_hh.set("gl", 0.0003);
+    soma_hh.set("el", -54.3);
+
+    // check that parameter values were set correctly
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("gnabar").value, 0.12);
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("gkbar").value, 0.036);
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("gl").value, 0.0003);
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("el").value, -54.3);
+
+    cell.segment(1)->set_compartments(10);
+
+    using fvm_cell = fvm::fvm_multicell<double, cell_lid_type>;
+    std::vector<fvm_cell::target_handle> targets;
+    std::vector<fvm_cell::detector_handle> detectors;
+    std::vector<fvm_cell::probe_handle> probes;
+
+    fvm_cell fvcell;
+    fvcell.initialize(util::singleton_view(cell), detectors, targets, probes);
+
+    auto& J = fvcell.jacobian();
+    EXPECT_EQ(J.size(), 11u);
+
+    fvcell.setup_matrix(0.01);
+}
+
+TEST(fvm_multi, multi_init)
+{
+    using namespace nest::mc;
+
+    nest::mc::cell cells[] = {
+        make_cell_ball_and_stick(),
+        make_cell_ball_and_3sticks()
+    };
+
+    EXPECT_EQ(cells[0].num_segments(), 2u);
+    EXPECT_EQ(cells[0].segment(1)->num_compartments(), 4u);
+    EXPECT_EQ(cells[1].num_segments(), 4u);
+    EXPECT_EQ(cells[1].segment(1)->num_compartments(), 4u);
+    EXPECT_EQ(cells[1].segment(2)->num_compartments(), 4u);
+    EXPECT_EQ(cells[1].segment(3)->num_compartments(), 4u);
+
+    cells[0].add_synapse({1, 0.4}, parameter_list("expsyn"));
+    cells[0].add_synapse({1, 0.4}, parameter_list("expsyn"));
+    cells[1].add_synapse({2, 0.4}, parameter_list("exp2syn"));
+    cells[1].add_synapse({3, 0.4}, parameter_list("expsyn"));
+
+    cells[1].add_detector({0, 0}, 3.3);
+
+    using fvm_cell = fvm::fvm_multicell<double, cell_lid_type>;
+    std::vector<fvm_cell::target_handle> targets(4);
+    std::vector<fvm_cell::detector_handle> detectors(1);
+    std::vector<fvm_cell::probe_handle> probes;
+
+    fvm_cell fvcell;
+    fvcell.initialize(cells, detectors, targets, probes);
+
+    auto& J = fvcell.jacobian();
+    EXPECT_EQ(J.size(), 5u+13u);
+
+    // check indices in instantiated mechanisms
+    for (const auto& mech: fvcell.mechanisms()) {
+        if (mech->name()=="hh") {
+            // HH on somas of two cells, with group compartment indices
+            // 0 and 5.
+            ASSERT_EQ(mech->node_index().size(), 2u);
+            EXPECT_EQ(mech->node_index()[0], 0u);
+            EXPECT_EQ(mech->node_index()[1], 5u);
+        }
+        if (mech->name()=="expsyn") {
+            // Three expsyn synapses, two in second compartment
+            // of dendrite segment of first cell, one in second compartment
+            // of last segment of second cell.
+            ASSERT_EQ(mech->node_index().size(), 3u);
+            EXPECT_EQ(mech->node_index()[0], 2u);
+            EXPECT_EQ(mech->node_index()[1], 2u);
+            EXPECT_EQ(mech->node_index()[2], 15u);
+        }
+        if (mech->name()=="exp2syn") {
+            // One exp2syn synapse, in second compartment
+            // of penultimate segment of second cell.
+            ASSERT_EQ(mech->node_index().size(), 1u);
+            EXPECT_EQ(mech->node_index()[0], 11u);
+        }
+    }
+
+    fvcell.setup_matrix(0.01);
+}
diff --git a/tests/validation/validate_ball_and_stick.cpp b/tests/validation/validate_ball_and_stick.cpp
index aa5102eabfc6131fa0bc6d12893cf5c257339836..da34cfcff48d5bae6829edf81140b322c7a7c107 100644
--- a/tests/validation/validate_ball_and_stick.cpp
+++ b/tests/validation/validate_ball_and_stick.cpp
@@ -7,6 +7,8 @@
 #include <util/range.hpp>
 
 #include "gtest.h"
+
+#include "../test_common_cells.hpp"
 #include "../test_util.hpp"
 #include "validation_data.hpp"
 
@@ -16,20 +18,7 @@ TEST(ball_and_stick, neuron_baseline)
     using namespace nest::mc;
     using namespace nlohmann;
 
-    nest::mc::cell cell;
-
-    // Soma with diameter 12.6157 um and HH channel
-    auto soma = cell.add_soma(12.6157/2.0);
-    soma->add_mechanism(hh_parameters());
-
-    // add dendrite of length 200 um and diameter 1 um with passive channel
-    auto dendrite = cell.add_cable(0, segmentKind::dendrite, 0.5, 0.5, 200);
-    dendrite->add_mechanism(pas_parameters());
-
-    dendrite->mechanism("membrane").set("r_L", 100);
-
-    // add stimulus
-    cell.add_stimulus({1,1}, {5., 80., 0.3});
+    nest::mc::cell cell = make_cell_ball_and_stick();
 
     // load data from file
     auto cell_data = testing::g_validation_data.load("ball_and_stick.json");
@@ -89,10 +78,10 @@ TEST(ball_and_stick, neuron_baseline)
     std::vector<fvm_cell::probe_handle> probes(cell.probes().size());
 
     std::vector<result> results;
-    for(auto run_index=0u; run_index<cell_data.size(); ++run_index) {
+    for (auto run_index=0u; run_index<cell_data.size(); ++run_index) {
         auto& run = cell_data[run_index];
         int num_compartments = run["nseg"];
-        dendrite->set_compartments(num_compartments);
+        cell.segment(1)->set_compartments(num_compartments);
         std::vector<std::vector<double>> v(3);
 
         // make the lowered finite volume cell
@@ -164,26 +153,7 @@ TEST(ball_and_3stick, neuron_baseline)
     using namespace nest::mc;
     using namespace nlohmann;
 
-    nest::mc::cell cell;
-
-    // Soma with diameter 12.6157 um and HH channel
-    auto soma = cell.add_soma(12.6157/2.0);
-    soma->add_mechanism(hh_parameters());
-
-    // add dendrite of length 200 um and diameter 1 um with passive channel
-    std::vector<cable_segment*> dendrites;
-    dendrites.push_back(cell.add_cable(0, segmentKind::dendrite, 0.5, 0.5, 100));
-    dendrites.push_back(cell.add_cable(1, segmentKind::dendrite, 0.5, 0.5, 100));
-    dendrites.push_back(cell.add_cable(1, segmentKind::dendrite, 0.5, 0.5, 100));
-
-    for(auto dend : dendrites) {
-        dend->add_mechanism(pas_parameters());
-        dend->mechanism("membrane").set("r_L", 100);
-    }
-
-    // add stimulus
-    cell.add_stimulus({2,1}, {5.,  80., 0.45});
-    cell.add_stimulus({3,1}, {40., 10.,-0.2});
+    nest::mc::cell cell = make_cell_ball_and_3sticks();
 
     // load data from file
     auto cell_data = testing::g_validation_data.load("ball_and_3stick.json");
@@ -247,8 +217,10 @@ TEST(ball_and_3stick, neuron_baseline)
     for(auto run_index=0u; run_index<cell_data.size(); ++run_index) {
         auto& run = cell_data[run_index];
         int num_compartments = run["nseg"];
-        for(auto dend : dendrites) {
-            dend->set_compartments(num_compartments);
+        for (auto& seg: cell.segments()) {
+            if (seg->is_dendrite()) {
+                seg->set_compartments(num_compartments);
+            }
         }
         std::vector<std::vector<double>> v(3);
 
diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp
index b5b1517fcfdd1878c5386b89bf55cb2b4cec2d11..8952ba30c93d5c7121fa09c6092e281d39564eb4 100644
--- a/tests/validation/validate_soma.cpp
+++ b/tests/validation/validate_soma.cpp
@@ -7,7 +7,9 @@
 #include <util/range.hpp>
 
 #include "gtest.h"
+
 #include "../test_util.hpp"
+#include "../test_common_cells.hpp"
 #include "validation_data.hpp"
 
 // compares results with those generated by nrn/soma.py
@@ -17,15 +19,7 @@ TEST(soma, neuron_baseline)
     using namespace nest::mc;
     using namespace nlohmann;
 
-    nest::mc::cell cell;
-
-    // Soma with diameter 18.8um and HH channel
-    auto soma = cell.add_soma(18.8/2.0);
-    soma->mechanism("membrane").set("r_L", 123); // no effect for single compartment cell
-    soma->add_mechanism(hh_parameters());
-
-    // add stimulus to the soma
-    cell.add_stimulus({0,0.5}, {10., 100., 0.1});
+    nest::mc::cell cell = make_cell_soma_only();
 
     // make the lowered finite volume cell
     using fvm_cell = fvm::fvm_cell<double, cell_local_size_type>;
@@ -86,15 +80,7 @@ TEST(soma, convergence)
 {
     using namespace nest::mc;
 
-    nest::mc::cell cell;
-
-    // Soma with diameter 18.8um and HH channel
-    auto soma = cell.add_soma(18.8/2.0);
-    soma->mechanism("membrane").set("r_L", 123); // no effect for single compartment cell
-    soma->add_mechanism(hh_parameters());
-
-    // add stimulus to the soma
-    cell.add_stimulus({0,0.5}, {10., 100., 0.1});
+    nest::mc::cell cell = make_cell_soma_only();
 
     // make the lowered finite volume cell
     using fvm_cell = fvm::fvm_cell<double, cell_local_size_type>;