单元测试调用HasDbFunction()时出现对象状态无效操作异常
问题解决思路
你的错误根源是:单元测试时EF Core内存提供者无法解析自定义DbFunction,直接执行了OracleDbFunctions.LPad方法体里的throw语句,导致报错。不需要初始化静态的OracleDbFunctions类,解决方法如下:
方法一:为单元测试注册DbFunction的内存实现
在测试用的DbContext配置中,为LPad函数添加内存翻译逻辑,模拟Oracle的LPad行为:
- 先写一个模拟Oracle LPad逻辑的静态方法:
public static class TestDbFunctionMocks { public static string MockLPad(string text, int totalWidth, string padding) { if (text == null) text = string.Empty; if (totalWidth <= text.Length) return text; if (string.IsNullOrEmpty(padding)) padding = " "; int padLength = totalWidth - text.Length; StringBuilder padBuilder = new(); while (padBuilder.Length < padLength) { padBuilder.Append(padding); } return padBuilder.ToString(0, padLength) + text; } }
- 在测试的DbContext配置中更新DbFunction注册:
modelBuilder.HasDbFunction(() => OracleDbFunctions.LPad(default, default, default)) .HasTranslation(args => Expression.Call( typeof(TestDbFunctionMocks), nameof(TestDbFunctionMocks.MockLPad), Type.EmptyTypes, args[0], args[1], args[2] ) );
这样EF Core在单元测试时会调用模拟方法,而不是执行原方法的throw语句。
方法二:改用集成测试
如果单元测试难以模拟复杂的数据库函数逻辑,可以直接连接真实的Oracle数据库做集成测试,这样就能复用原有的DbFunction配置,避免模拟逻辑的偏差。
补充说明
实际运行时EF Core会把OracleDbFunctions.LPad转换为Oracle的LPAD SQL语句,不会执行方法体;但内存数据库无法识别自定义DbFunction,会直接执行方法体代码,这就是你看到异常的原因。
内容的提问来源于stack exchange,提问作者Taran
相关产品推荐
相关产品推荐

