Wait for a static value to appear
Some other improvements:


Check ExternalValueContainer.Value synchronously first. If it already exist then you can return early, and there is no reason to await anything. (Note eurotrash's point about thread safety).
If value is never set, getValueTask never returns. Instead of waiting for delayTask separately, you should check the timeout inside getValueTask's body and return once timeout is exceeded.


In general I feel like proper unit tests should not use delays and should not rely on them. Not only because those 5s delays quickly add up if you run this method multiple times, but also because the behavior of unit tests becomes unpredictable. The same test can fail on one machine and pass on another, simply because on one machine GetStringValueOrNull() timed out, while on the other - it did not. IMHO you should take it as signal, that you design is flawed and should be changed. If you own ExternalValueContainer, then you should probably modify its API so consumer can wait for the value (using async methods, events, observables or any other suitable tool). If you do not own ExternalValueContainer then you should wrap it in non-static service and mock this service in your tests.