See It Run
Input → lookup → branch → mutation → output. State before and after with exactly what changed; the flowchart of an operation; debugging an implementation from expected state to the wrong assumption; and "why does this exist?" for every field and function.
Every call to addItem passes through the same five stops. Tracing one call by hand — what came in, what was looked up, which way it went, what was changed, what went back — is how you find out whether the function you wrote is the operation you meant.
A state change you cannot describe as "this field went from this to that" is one you have not seen. Put the state before, the operation, and the state after side by side, and name every difference — there are usually fewer than you think, and occasionally one more.
addItem has two decisions and three exits, and every one of them is a rule. A flowchart of one operation is a map of its branches — which is a list of the cases the tests need and a picture of which order the checks run in.
A wrong cart is not "broken"; it is a specific expected state, a specific actual state, one operation that turned the first into the second, one branch inside it that ran when another should have, and one assumption that made you write it that way. Five questions, in that order, and the bug has nowhere to hide.
Every class, function and field in the cart answers three questions: why is it here, what problem does it solve, what breaks if it is removed. A line that cannot answer them is cargo — it came from somewhere, it might be load-bearing, and nobody can tell.