如何在C#单元测试中正确调用Nethereum的GetTransactionCount异步方法
解决异步获取TransactionCount的单元测试问题
首先,你的单元测试里用Wait()是核心问题之一——在异步方法里直接调用Wait()很容易引发死锁,还没法正确拿到异步任务的结果。咱们可以通过下面几个步骤来修复:
1. 用await替代Wait()调用异步方法
你的单元测试方法已经标记为async Task,直接用await就能获取GetTxCount的结果,完全不需要手动调用Wait():
[TestMethod] public async Task TestMethodAsync() { string address = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae"; EthTest.Eth et = new EthTest.Eth(); // 用await获取异步结果,这里可以强转成ulong(交易数量是无符号整数类型) var txCount = await et.GetTxCount(address).ConfigureAwait(false); // 可以加个断言验证结果合理性,比如交易数不会是负数 Assert.IsTrue((ulong)txCount >= 0); }
2. 优化GetTxCount的返回类型
你现在的GetTxCount返回Task<object>,其实可以更明确地返回Task<ulong>,这样单元测试里不用强制转换,代码也更清晰:
public async Task<ulong> GetTxCount(string address) { return await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address).ConfigureAwait(false); }
对应的单元测试可以简化成:
[TestMethod] public async Task TestMethodAsync() { string address = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae"; EthTest.Eth et = new EthTest.Eth(); ulong txCount = await et.GetTxCount(address).ConfigureAwait(false); Assert.IsTrue(txCount >= 0); }
3. 排查Web3实例的初始化问题
如果改完还是没调用Nethereum的API,那大概率是EthTest.Eth类里的web3实例没正确初始化。一定要确保你连接到了有效的以太坊节点,比如在类的构造函数里初始化:
public Eth() { // 替换成你的节点地址,比如Infura的主网/测试网节点,或者本地Ganache节点 string nodeUrl = "https://mainnet.infura.io/v3/你的项目ID"; web3 = new Web3(nodeUrl); }
要是节点地址无效或者没网络,SendRequestAsync会直接失败,看起来就像没调用API一样。可以在单元测试里加个异常捕获,方便排查具体错误:
[TestMethod] public async Task TestMethodAsync() { try { string address = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae"; EthTest.Eth et = new EthTest.Eth(); ulong txCount = await et.GetTxCount(address).ConfigureAwait(false); Assert.IsTrue(txCount >= 0); } catch(Exception ex) { // 打印异常信息,方便定位问题 Console.WriteLine($"出错了:{ex.Message}"); throw; // 重新抛出异常让单元测试失败,同时保留错误详情 } }
为啥Wait()会出问题?
在有SynchronizationContext的环境(比如部分单元测试框架)里,Task.Wait()会阻塞当前线程,而异步任务完成后需要回到原来的上下文,这就会造成死锁——阻塞的线程等着任务完成,任务又等着阻塞的线程释放上下文。用await则会正确释放上下文,从根源避免死锁。
内容的提问来源于stack exchange,提问作者Peter PitLock
相关产品推荐
相关产品推荐

