如何为插值字符串设置Mock?Logger接口单元测试疑问
Absolutely—but it depends on how your ILogger.Trace method is defined. Let me break this down clearly for you:
The Default Problem: Interpolated Strings as string
If your Trace method accepts a string parameter like this:
public interface ILogger { void Trace(string message); }
When you call logger.Trace($"User {userId} performed action {action}"), the C# compiler converts the interpolated string directly into a fully resolved string at compile time. By the time it reaches your mock, only the final concatenated text exists—there’s no way to recover the original template (like "User {userId} performed action {action}").
The Clean Solution: Use FormattableString
To capture the original interpolation template, modify your ILogger interface to accept a FormattableString instead of string:
public interface ILogger { void Trace(FormattableString message); }
FormattableString preserves both the raw template string and the individual values being interpolated. This lets your mock verify the exact template used, without tying your test to specific parameter values (great for keeping tests flexible).
Example with Moq
Here’s how you’d set up and verify the mock in your unit test:
// Arrange var mockLogger = new Mock<ILogger>(); var service = new YourService(mockLogger.Object); var userId = 123; var action = "update"; // Act service.DoSomeWork(userId, action); // Assert: Verify the exact template was used mockLogger.Verify( l => l.Trace(It.Is<FormattableString>(fs => fs.Format == "User {0} performed action {1}" )), Times.Once );
You can even go further and validate the interpolated values if needed:
mockLogger.Verify( l => l.Trace(It.Is<FormattableString>(fs => fs.Format == "User {0} performed action {1}" && fs.GetArgument(0).Equals(userId) && fs.GetArgument(1).Equals(action) )), Times.Once );
Workarounds If You Can’t Modify the Interface
If changing the ILogger interface isn’t an option, your next best bet is to use fuzzy matching on the resolved string (e.g., checking if it contains expected substrings):
mockLogger.Verify( l => l.Trace(It.Is<string>(s => s.Contains($"User {userId}") && s.Contains("performed action") )), Times.Once );
This is less reliable than using FormattableString (since other unrelated strings could match), but it works as a fallback if you can’t adjust the interface.
内容的提问来源于stack exchange,提问作者sethlj11

