Dictionary Assertions
TUnit provides specialized assertions for testing dictionaries (IReadOnlyDictionary<TKey, TValue>), including key and value membership checks. Dictionaries also inherit all collection assertions.
Key Assertionsâ
ContainsKeyâ
Tests that a dictionary contains a specific key:
[Test]
public async Task Dictionary_Contains_Key()
{
var dict = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2,
["cherry"] = 3
};
await Assert.That(dict).ContainsKey("apple");
await Assert.That(dict).ContainsKey("banana");
}
With Custom Comparerâ
[Test]
public async Task Contains_Key_With_Comparer()
{
var dict = new Dictionary<string, int>
{
["Apple"] = 1,
["Banana"] = 2
};
await Assert.That(dict)
.ContainsKey("apple")
.Using(StringComparer.OrdinalIgnoreCase);
}
DoesNotContainKeyâ
Tests that a dictionary does not contain a specific key:
[Test]
public async Task Dictionary_Does_Not_Contain_Key()
{
var dict = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2
};
await Assert.That(dict).DoesNotContainKey("cherry");
await Assert.That(dict).DoesNotContainKey("orange");
}
Value Assertionsâ
ContainsValueâ
Tests that a dictionary contains a specific value:
[Test]
public async Task Dictionary_Contains_Value()
{
var dict = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2,
["cherry"] = 3
};
await Assert.That(dict).ContainsValue(2);
await Assert.That(dict).ContainsValue(3);
}
Collection Assertions on Dictionariesâ
Dictionaries inherit all collection assertions since they implement IEnumerable<KeyValuePair<TKey, TValue>>:
Countâ
[Test]
public async Task Dictionary_Count()
{
var dict = new Dictionary<string, int>
{
["a"] = 1,
["b"] = 2,
["c"] = 3
};
await Assert.That(dict).Count().IsEqualTo(3);
}
IsEmpty / IsNotEmptyâ
[Test]
public async Task Dictionary_Empty()
{
var empty = new Dictionary<string, int>();
var populated = new Dictionary<string, int> { ["key"] = 1 };
await Assert.That(empty).IsEmpty();
await Assert.That(populated).IsNotEmpty();
}
Contains (KeyValuePair)â
[Test]
public async Task Dictionary_Contains_Pair()
{
var dict = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2
};
await Assert.That(dict).Contains(new KeyValuePair<string, int>("apple", 1));
}
All Pairs Match Conditionâ
[Test]
public async Task All_Values_Positive()
{
var dict = new Dictionary<string, int>
{
["a"] = 1,
["b"] = 2,
["c"] = 3
};
await Assert.That(dict).All(kvp => kvp.Value > 0);
}
Any Pair Matches Conditionâ
[Test]
public async Task Any_Key_Starts_With()
{
var dict = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2,
["cherry"] = 3
};
await Assert.That(dict).Any(kvp => kvp.Key.StartsWith("b"));
}
Practical Examplesâ
Configuration Validationâ
[Test]
public async Task Configuration_Has_Required_Keys()
{
var config = LoadConfiguration();
await using (Assert.Multiple())
{
await Assert.That(config).ContainsKey("DatabaseConnection");
await Assert.That(config).ContainsKey("ApiKey");
await Assert.That(config).ContainsKey("Environment");
}
}
HTTP Headers Validationâ
[Test]
public async Task Response_Headers()
{
var headers = new Dictionary<string, string>
{
["Content-Type"] = "application/json",
["Cache-Control"] = "no-cache"
};
await Assert.That(headers)
.ContainsKey("Content-Type")
.And.ContainsValue("application/json");
}
Lookup Table Validationâ
[Test]
public async Task Lookup_Table()
{
var statusCodes = new Dictionary<int, string>
{
[200] = "OK",
[404] = "Not Found",
[500] = "Internal Server Error"
};
await Assert.That(statusCodes)
.Count().IsEqualTo(3)
.And.ContainsKey(200)
.And.ContainsValue("OK");
}
Cache Validationâ
[Test]
public async Task Cache_Contains_Entry()
{
var cache = new Dictionary<string, object>
{
["user:123"] = new User { Id = 123 },
["user:456"] = new User { Id = 456 }
};
await Assert.That(cache)
.ContainsKey("user:123")
.And.Count().IsEqualTo(2)
.And.IsNotEmpty();
}
Dictionary Key/Value Operationsâ
Accessing Values After Key Checkâ
[Test]
public async Task Get_Value_After_Key_Check()
{
var dict = new Dictionary<string, User>
{
["alice"] = new User { Name = "Alice", Age = 30 }
};
// First verify key exists
await Assert.That(dict).ContainsKey("alice");
// Then safely access
var user = dict["alice"];
await Assert.That(user.Age).IsEqualTo(30);
}
TryGetValue Patternâ
[Test]
public async Task TryGetValue_Pattern()
{
var dict = new Dictionary<string, int>
{
["count"] = 42
};
var found = dict.TryGetValue("count", out var value);
await Assert.That(found).IsTrue();
await Assert.That(value).IsEqualTo(42);
}
Working with Dictionary Keys and Valuesâ
Keys Collectionâ
[Test]
public async Task Dictionary_Keys()
{
var dict = new Dictionary<string, int>
{
["a"] = 1,
["b"] = 2,
["c"] = 3
};
var keys = dict.Keys;
await Assert.That(keys)
.Count().IsEqualTo(3)
.And.Contains("a")
.And.Contains("b")
.And.Contains("c");
}
Values Collectionâ
[Test]
public async Task Dictionary_Values()
{
var dict = new Dictionary<string, int>
{
["a"] = 1,
["b"] = 2,
["c"] = 3
};
var values = dict.Values;
await Assert.That(values)
.Count().IsEqualTo(3)
.And.Contains(1)
.And.Contains(2)
.And.All(v => v > 0);
}
Equivalency Checksâ
Same Key-Value Pairsâ
[Test]
public async Task Dictionaries_Are_Equivalent()
{
var dict1 = new Dictionary<string, int>
{
["a"] = 1,
["b"] = 2
};
var dict2 = new Dictionary<string, int>
{
["b"] = 2,
["a"] = 1
};
// Dictionaries are equivalent (same pairs, order doesn't matter)
await Assert.That(dict1).IsEquivalentTo(dict2);
}
Chaining Dictionary Assertionsâ
[Test]
public async Task Chained_Dictionary_Assertions()
{
var dict = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2,
["cherry"] = 3
};
await Assert.That(dict)
.IsNotEmpty()
.And.Count().IsEqualTo(3)
.And.ContainsKey("apple")
.And.ContainsKey("banana")
.And.ContainsValue(2)
.And.All(kvp => kvp.Value > 0);
}
Specialized Dictionary Typesâ
ConcurrentDictionaryâ
[Test]
public async Task Concurrent_Dictionary()
{
var concurrent = new ConcurrentDictionary<string, int>();
concurrent.TryAdd("a", 1);
concurrent.TryAdd("b", 2);
await Assert.That(concurrent)
.Count().IsEqualTo(2)
.And.ContainsKey("a");
}
ReadOnlyDictionaryâ
[Test]
public async Task ReadOnly_Dictionary()
{
var dict = new Dictionary<string, int> { ["a"] = 1 };
var readOnly = new ReadOnlyDictionary<string, int>(dict);
await Assert.That(readOnly)
.Count().IsEqualTo(1)
.And.ContainsKey("a");
}
SortedDictionaryâ
[Test]
public async Task Sorted_Dictionary()
{
var sorted = new SortedDictionary<int, string>
{
[3] = "three",
[1] = "one",
[2] = "two"
};
var keys = sorted.Keys.ToArray();
await Assert.That(keys).IsInOrder();
}
Null Checksâ
Null Dictionaryâ
[Test]
public async Task Null_Dictionary()
{
Dictionary<string, int>? dict = null;
await Assert.That(dict).IsNull();
}
Empty vs Nullâ
[Test]
public async Task Empty_vs_Null_Dictionary()
{
Dictionary<string, int>? nullDict = null;
var emptyDict = new Dictionary<string, int>();
await Assert.That(nullDict).IsNull();
await Assert.That(emptyDict).IsNotNull();
await Assert.That(emptyDict).IsEmpty();
}
Common Patternsâ
Required Configuration Keysâ
[Test]
public async Task All_Required_Keys_Present()
{
var config = LoadConfiguration();
var requiredKeys = new[] { "ApiKey", "Database", "Environment" };
foreach (var key in requiredKeys)
{
await Assert.That(config).ContainsKey(key);
}
}
Or with Assert.Multiple:
[Test]
public async Task All_Required_Keys_Present_Multiple()
{
var config = LoadConfiguration();
var requiredKeys = new[] { "ApiKey", "Database", "Environment" };
await using (Assert.Multiple())
{
foreach (var key in requiredKeys)
{
await Assert.That(config).ContainsKey(key);
}
}
}
Metadata Validationâ
[Test]
public async Task Validate_Metadata()
{
var metadata = GetFileMetadata();
await Assert.That(metadata)
.ContainsKey("ContentType")
.And.ContainsKey("Size")
.And.ContainsKey("LastModified")
.And.All(kvp => kvp.Value != null);
}
Feature Flagsâ
[Test]
public async Task Feature_Flags()
{
var features = new Dictionary<string, bool>
{
["NewUI"] = true,
["BetaFeature"] = false,
["ExperimentalApi"] = true
};
await Assert.That(features)
.ContainsKey("NewUI")
.And.ContainsValue(true);
var newUiEnabled = features["NewUI"];
await Assert.That(newUiEnabled).IsTrue();
}
See Alsoâ
- Collections - General collection assertions
- Equality & Comparison - Comparing dictionary values
- Strings - String key comparisons