gpt4 book ai didi

c# - 单元测试 EF DbUpdateConcurrencyException 处理

转载 作者:太空宇宙 更新时间:2023-11-03 13:55:36 26 4
gpt4 key购买 nike

我需要帮助测试以下代码

public virtual void Update(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}

int iretries = 0;
bool success = false;

do
{
try
{
this.context.SaveChanges();
success = true;
}
catch (DbUpdateConcurrencyException ex)
{
// Get the current entity values and the values in the database
// as instances of the entity type
var entry = ex.Entries.Single();
var databaseValues = entry.GetDatabaseValues();

// Choose an initial set of resolved values. In this case we
// make the default be the values currently in the database: StoreWins
object resolvedValues = ResolveConcurrency(databaseValues.ToObject());

// Update the original values with the database values and
// the current values with whatever the user choose.
entry.OriginalValues.SetValues(databaseValues);
entry.CurrentValues.SetValues(resolvedValues);

// give up after n retries
if (++iretries == NUMBER_OF_CONC_RETRIES)
throw;
}
catch (Exception)
{
//rethrow
throw;
}
} while (!success);
}

我想对 DbUpdateConcurrencyException 进行单元测试分支机构。

因此,一个简单的测试场景是:

  • 正在创建一个新的 DbUpdateConcurrencyException
  • 模拟SaveChanges抛出上述异常
  • 验证SaveChanges被称为数NUMBER_OF_CONC_RETRIES
  • 断言 Update方法重新抛出异常

在当前状态下,无法测试上述测试场景,我无法模拟包含 IEnumerable<DbEntityEntry> 的异常。用一个DbEntityEntry ;我不能 mock GetDatabaseValues()

一个简单的解决方案是插入一个新的抽象层;假设使用一个接口(interface)来抽象当前位于 catch block 中的整个代码,并提供一个什么也不做的模拟。

但是当我想测试该接口(interface)的实现时,我最终会遇到与上述相同的问题。我怎样才能模拟 DbUpdateConcurrencyException , GetDatabaseValues

我正在使用最小起订量进行模拟。

感谢您的参与

最佳答案

如果你不能模拟某些东西,你必须将它隐藏在其他你可以在测试中模拟或覆盖的东西后面。您的测试实际上不需要使用所有这些东西来加载值并在条目中设置它们——这完全取决于 EF,并且在模拟上下文时您不会测试它,因为这意味着重新实现 EF 背后的逻辑 保存更改。您需要做的就是:

catch (DbUpdateConcurrencyException ex) {
RefreshValues(ex);

// give up after n retries
if (++iretries == NUMBER_OF_CONC_RETRIES)
throw;
}

RefreshValues 可以是 protected virtual 方法,您可以在测试中覆盖它,方法是提供类的测试版本(您甚至可以使用 Moq 实现)或通过从此类继承测试并直接在测试类中覆盖方法。

要设置 Moq,您需要为您的上下文公开 SaveChanges 方法的接口(interface):

var contextMock = new Mock<IContext>();
contextMock.Setup(m => m.SaveChanges())
.Callback(m => throw new DbUpdateConcurrencyException());

如果您需要测试它是否也适用于几次抛出,您需要在测试中保持计数器并在回调中使用它来决定是否抛出。

关于c# - 单元测试 EF DbUpdateConcurrencyException 处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12314704/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com