Expansion is simply half of how TeX works, so this is not going to be an easy answer.
First of all, TeX operates on tokens (see What is a token?). A token can be either expandable or unexpandable; if it's unexpandable, it obviously never expands, otherwise it can expand. What an expandable token expands to depends on how it has been made part of the language.
Some primitive (that is, whose meaning is predeclared when TeX starts from scratch) tokens are expandable, some aren't. Among the expandable primitives one finds \expandafter, \if and all other conditionals; this was predictable, as these primitive are used to control the expansion process itself; the expansion of an expandable primitive can be void, but it can trigger some other action. All macros defined with \def (along with its variants \gdef, \edef or \xdef) are expandable and their expansion is precisely the replacement text.
So, assume we have
\def\test{some text}
or, in LaTeX, \newcommand\test{some text} which is pretty similar. Under normal operations, if TeX finds
Here is \test
it will absorb Here<space>is<space> (eight unexpandable tokens) and stop at \test, examine it and decide that it is expandable (TeX uses the current meaning of \test), so it replaces it by some text and goes on starting from “s”. Since this token is unexpandable, it's handed over to another phase of processing and TeX goes on with “o” and so on.
Now, suppose that we have
\def\test{\foo{o}me text}
\def\foo#1{s#1}
an input such as
Here is \test
would make TeX hand over tokens up to finding \test, which it would replace with
\foo{o}me text
and \foo would now be expanded to so, after having absorbed its argument.
I said “normal operations”, because in some cases expansion is inhibited:
when TeX is looking for macro arguments;
when TeX is doing a definition with \def or \gdef, with regard to the macro to be defined, the parameter text and the replacement text;
when TeX is doing a definition with \edef or \xdef, but this only concerns the macro to be defined and the parameter text, not the replacement text;
when TeX is examining the token to be defined after \let, \chardef, \mathchardef and all other \...def commands;
when TeX is examining the “right hand side” of a \let;
when TeX is absorbing the tokens for \write, \uppercase, \lowercase, \detokenize, \unexpanded or an assignment to a token register.
Sometimes we talk about "full expansion". What's that? When we do
\edef\baz{<tokens>}
the <tokens> are subject to expansion, the resulting token list is subject to expansion and so on, until only unexpandable tokens remain, always starting from the next token as explained before. After this, the definition is performed, using the token list thus obtained as replacement text. Thus, with the definition above,
\edef\baz{\test}
would expand \test to \foo{o}me text and this to some text, resulting in the same as if we said \def\baz{some text}. Why should we want to do in this way? Because TeX uses the current meaning of the tokens; if we said
\def\baz{\test}
and later change the definition of \foo (or of \test, of course), the macro \baz would expand to something else; with \edef we're sure it expands to some text.
However, \edef doesn't perform assignments. So if we do
\count255=1
\edef\baz{\advance\count255 by 1 \number\count255 }
using \baz would print 1, not 2. This is because \advance and \count are not expandable; character tokens aren't expandable either; \number is expandable and its expansion is the decimal representation of the <number> following it. So this \edef is just equivalent to
\def\baz{\advance\count255 by 1 1}
The same happens when, ultimately, TeX expands the token list in a \write: the expansion is performed "all the way", just like in \edef. Expansion of tokens can be inhibited by preceding the one we don't want to expand with \noexpand or enclosing them as the argument to \unexpanded. Note that this is just a “one shot” activity: if one does
\def\a{A}\def\b{B}\def\c{C}
\edef\foo{\a\b\noexpand\c}
the replacement text for \foo will be AB\c; upon usage of \foo, \c will be expanded according to its current meaning.
Also tokens appearing after \csname and before the matching \endcsname are subject to full expansion; in this case only character tokens must remain, so a \relax is illegal here, while it wouldn't be in \edef or \write.
Complicated? Yes.