Let $o(a)$ denote the order of $a$ in the group $(\mathbf{Z}/p\mathbf{Z})^\times$
and let $\nu_q(n)$ be the biggest power of $q$ dividing $n$.
So, $o(a) = \min\{k\ge 1 : a^k = 1\}$ and $\nu_q(n) = \max\{k\ge 0 : q^k\mid n\}$.
A relatively quick test is the following: if $a^{(p-1)/q} \ne 1$ for every prime factor $q$ of $p-1$, then $a$ is a primitive root modulo $p$.
Proof. If $o(a) < p-1$, then, since the order of an element divides the order of the group, $o(a)\mid p-1$, which means $\nu_q(o(a)) \le \nu_q(p-1)$ for every prime $q$. Since $o(a)$ does not equal $p-1$, there must be a prime $q$ for which the inequality $\nu_q(o(a)) \le \nu_q(p-1)$ is strict, from which it follows that, for this prime $q$, $\nu_q(o(a)) \le \nu_q(p-1)-1$. This implies two things: that $q$ divides $p-1$ and that $o(a) \mid (p-1)/q$; the result follows by taking the contrapositive.
There is a (bit of a tedious) way to build primitive roots out of bad guesses. I'll prove its correctness as I describe it.
Take $a_0$ in $(\mathbf{Z}/p\mathbf{Z})^\times$ and suppose $n := o(a_0) < p-1$.
The subgroup $\langle a_0 \rangle$ generated by $a_0$ is the full set of roots of $X^n-1$ in $\mathbf{Z}/p\mathbf{Z}$;
if we pick some element $b_0$ not in $\langle a_0 \rangle$ then, necessarily, $b_0^n \ne 1$, which means that $o(b_0) =: m \nmid n$.
Thus, $e := \nu_q(m) > \nu_q(n) =: d$ for some prime $q$.
Define a new candidate for primitive-roothood by
$$\Large a_1 = a_0^{q^d}b_0^{m/q^e}.$$
By the formula $o(g^k) = o(g)/\gcd(o(g), k)$,
we see that $o(a_0^{q^d}) = n/q^d$ and $o(b_0^{m/q^e}) = q^e$.
Now, since $n/q^d$ and $q^e$ are coprime, $o(a_1) = nq^{e-d} > n = o(a_0)$!
It should be clear that if $o(a_1) < p-1$, we can repeat the process, picking $b_1$ as before, etc. This can't go on forever because there are only finitely many integers between $o(a_0)$ and $p - 1$!
Here's a sample computation.
Let $p = 19$ and let's guess $a_0 = 8$.
Since $\langle 8 \rangle = \{1, 8, 7, 18, 11, 12\}$,
we see that $n = o(8) = 6 < 18$.
Pick $b_0 = 5$ and note that $m = o(5) = 9$,
which does not divide $n = 6$ because $9$ has more $3$s in it.
Let $q = 3$, so that $e = 2$ and $d = 1$.
By the formula,
$$a_1 = a_0^{q^d}b_0^{m/q^e} = 8^{3^1} \cdot 5^{9/3^2} = 8^3\cdot 5^1 = 14$$
and $14$ has order $nq^{e-d} = 6\cdot 3^{2-1} = 18$, so it is a primitive root.