devlooped/moq · error · ArgumentNullException

ArgumentNullException: Value cannot be null. (Parameter…

Error message

ArgumentNullException: Value cannot be null. (Parameter 'random')

What it means

This ReturnsAsync overload for Task<TResult> with randomized min/max delay requires a non-null Random instance because it generates a random delay via GetDelay(minDelay, maxDelay, random). Passing null throws ArgumentNullException with parameter name 'random' immediately at setup time.

Solutions

  1. Pass a Random instance, e.g. new Random(12345) for a reproducible seeded generator
  2. If no randomness is wanted, use the ReturnsAsync(value, delay) overload with a fixed TimeSpan instead

Example fix

// before
mock.Setup(m => m.GetAsync()).ReturnsAsync(result, TimeSpan.Zero, TimeSpan.FromSeconds(1), null);
// after
mock.Setup(m => m.GetAsync()).ReturnsAsync(result, TimeSpan.Zero, TimeSpan.FromSeconds(1), new Random(42));
Defensive patterns

Strategy: validation

Validate before calling

if (random is null) throw new ArgumentException("ReturnsAsync with min/max delay requires a Random instance");

Type guard

bool HasRandom(Random? r) => r is not null;

Try / catch

try { mock.Setup(m => m.GetAsync()).ReturnsAsync(v, min, max, random); } catch (ArgumentNullException ex) when (ex.ParamName == "random") { /* pass a Random or fixed delay */ }

Prevention

When it happens

Trigger: mock.Setup(x => x.GetDataAsync()).ReturnsAsync(value, minDelay, maxDelay, null) — the four-argument overload with a null Random.

Common situations: Refactoring from the no-arg ReturnsAsync(value) overload to the delayed overload and passing null 'just to get defaults'; test data builders supplying a null Random.

Related errors


AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16). Data as JSON: /api/errors/43372ec07c15e006. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/ReturnsExtensions.cs:195

        /// Allows to specify the delayed return value of an asynchronous method.
        /// </summary>
        public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, ValueTask<TResult>> mock,
            TResult value, TimeSpan minDelay, TimeSpan maxDelay) where TMock : class
        {
            var delay = GetDelay(minDelay, maxDelay, Random);

            return DelayedResult(mock, value, delay);
        }

        /// <summary>
        /// <para>Allows to specify the delayed return value of an asynchronous method.</para>
        /// <para>Use the <see cref="Random"/> argument to pass in (seeded) random generators used across your unit test.</para>
        /// </summary>
        public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, Task<TResult>> mock,
            TResult value, TimeSpan minDelay, TimeSpan maxDelay, Random random) where TMock : class
        {
            if (random == null)
                throw new ArgumentNullException(nameof(random));

            var delay = GetDelay(minDelay, maxDelay, random);

            return DelayedResult(mock, value, delay);
        }

        /// <summary>
        /// <para>Allows to specify the delayed return value of an asynchronous method.</para>
        /// <para>Use the <see cref="Random"/> argument to pass in (seeded) random generators used across your unit test.</para>
        /// </summary>
        public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, ValueTask<TResult>> mock,
            TResult value, TimeSpan minDelay, TimeSpan maxDelay, Random random) where TMock : class
        {
            if (random == null)
                throw new ArgumentNullException(nameof(random));

            var delay = GetDelay(minDelay, maxDelay, random);

View on GitHub (pinned to 89a5be629c)