In JMeter, how does a Module Controller find the fragment named in Module To Run?
answer
- The pointer is a path, not an id
- Names all the way down
- Rename anything and it breaks
- The run stops, it does not skip
basics
~10 sBy name, not by identifier. Module To Run stores the target's full path of element names from the tree root, and JMeter walks the tree matching those names when the test starts.
solid answer
~50 sPicking a target in *Module To Run* makes JMeter record the chain of element **names** from the tree root down to that controller, in the `ModuleController.node_path` collection property. At test start it walks the plan tree level by level, matching each name in turn, and the node it lands on is substituted in place of the Module Controller. Nothing is written onto the target itself. Two consequences follow. First, **renaming any element on that path** — the fragment or a parent — leaves the walk with nothing to match, and JMeter raises `JMeterStopTestException` with the message *"has no selected Controller (did you rename some element in the path to target controller?), test was shutdown as a consequence"*. Second, the manual's rule that fragments must have **unique names** is not style advice: the walk matches by name, and the last match wins silently.
code
text · 11 linesTest Plan
|- Login Fragment <- Test Fragment, disabled
| `- Login <- Simple Controller (the Module To Run target)
| |- POST /login
| `- Regular Expression Extractor: token
`- Checkout Thread Group
`- Run Login <- Module Controller
stored reference: ["Test Plan", "Test Plan", "Login Fragment", "Login"]
^^^^^^^^^^^ index 0 is the hidden tree root above the plan
(setRootVisible(false)); the walk starts at index 1go deeper
Know that Module To Run picks a controller already in this plan and that JMeter runs that branch in the Module Controller's place. The target does not have to be enabled.
Explain that the reference is stored as the chain of element names from the tree root, walked at test start, and that the picker excludes Module Controllers so a reference cannot recurse.
Recognise the failure by its message: an unresolved module reference throws a stop-test exception naming the controller, so a rename anywhere on the path takes the whole run down rather than one branch.
Own the naming discipline this implies across a team's plans. Default labels such as Simple Controller make duplicate paths likely, and duplicates resolve to the last match without warning anybody.
## The reference is a path of names When you choose a target in a Module Controller's *Module To Run* picker, `ModuleController.setSelectedNode()` calls `setNodePath()`, which walks the selected node's ancestry and stores every name it passes as a `CollectionProperty` under the key `ModuleController.node_path`. That is the whole of the reference. No identifier is generated, nothing is stamped on the target, and no file path is involved. The manual describes the same thing from the user's side: "A fragment name is made up of the Controller name and all its parent names", with the worked example `Test Plan / Protocol: JDBC / Control / Interleave Controller (Module1)`. ## How the walk runs `ModuleController.resolveReplacementSubTree()` reads that stored list and calls a recursive `traverse()` from the tree root, comparing each level's stored name against the children at that level. Three details of that walk matter in practice: - **Matching is by `getName()` equality.** Nothing else is compared — not type, not position. - **Module Controllers are skipped.** The traversal refuses to descend into or select a node that is itself a `ModuleController`, a guard added for Bugzilla 55375 to stop a module referencing a module and recursing. - **The last match wins.** If two siblings carry the same name, the loop keeps going and overwrites the selection with the later one, quietly. In a non-GUI run JMeter does this explicitly before conversion: `runNonGui()` searches the loaded tree for every `ReplaceableController` and calls `resolveReplacementSubTree(root)` on each — a step the source itself labels "Hack to resolve ModuleControllers in non GUI mode". ## What the picker will and will not offer The *Module To Run* control is a tree of the plan, filtered by `ModuleControllerGui.buildTreeNodeModel()` to four kinds of node: 1. the Test Plan, 2. Thread Groups, 3. Test Fragments, 4. any other Controller — **except** a Module Controller. So the target is always a controller-shaped node. You cannot point a Module Controller at a bare sampler, and you cannot point it at another Module Controller. The GUI also carries a *Find target element* button that jumps the main tree to whatever the picker currently selects, which is the fastest way to check that a reference still resolves. ## When resolution fails If the walk ends with no node selected and replacement is genuinely being attempted, the controller throws: > `ModuleController:<name> has no selected Controller (did you rename some element in the path to target controller?), test was shutdown as a consequence` That is a **stop-test** exception, not a skipped branch. A plan whose module reference has rotted does not quietly run a step short — it stops. That is the opposite of what an Include Controller does with a file it cannot load, and it is worth knowing which of the two you are dealing with when a pipeline goes red for no obvious reason. ## The login flow reused by three plans Suppose the login flow lives in a `Login Fragment` under the Test Plan, with a `Login` Simple Controller inside it, and three Module Controllers elsewhere in the plan point at it. Every one of those references stores the same list of names. Then someone renames the fragment to `Login v2` in a review: - the stored path still says `Login Fragment`; - the walk finds no such child of the Test Plan; - all three Module Controllers fail to resolve, and the first one hit shuts the run down. The practical guards are the ones the manual states: give the fragment and its controllers **distinct, deliberate names** rather than leaving `Simple Controller` as the label, and treat a rename as a change that has to be followed by re-picking every reference. ## Boundaries worth stating - A Module Controller only ever reaches inside the plan tree it was loaded with. It cannot name another `.jmx`; that is what an Include Controller is for. - Being disabled does not disqualify a target. `getReplacementSubTree()` clones a disabled node, enables the clone and returns that, which is exactly how a disabled Test Fragment can be run by reference. - The substitution happens once, while the test tree is converted, so the references cost nothing per iteration.
- Two Test Fragments in one JMeter plan share a name. What does a Module Controller pointing at one of them do?It resolves to whichever the tree lists later, with no warning. The traversal compares names at each level and overwrites its selection every time it matches, so the last sibling with that name wins. This is why the manual insists that fragments used by a Module Controller carry unique names.
- Can a JMeter Module Controller point at another Module Controller?No. The traversal explicitly skips any node that is a ModuleController, a guard added for Bugzilla 55375 to prevent recursive references, and the Module To Run picker leaves them out of the tree it shows. The picker offers the Test Plan, Thread Groups, Test Fragments and ordinary controllers only.
It is a filing-cabinet reference written as "second drawer, blue folder, third tab" rather than as a catalogue number. Relabel any one of those three things and the reference now points at nothing at all.
saying these in an interview costs you the question
- Says the Module Controller copies the fragment into the plan
- Thinks the reference survives renaming the target controller
- Believes Module To Run can name a fragment in another .jmx file
- Expects a broken module reference to be skipped rather than stop the run
- Assumes the target has to be enabled to be referenced