c# - 单元测试在 try catch block 中调用异步操作的 getter

标签 c# .net unit-testing windows-phone-8 async-await

我有以下代码:

public FuzzyPickles(IPie pieMaker)
{
    _pieMaker = pieMaker;
}  

public string PieName
{
    get
    {
        if (_pieName == null)
        {
            GetPieName();
        }
        return _pieName;
    }
}  

private async void GetPieName()
{
    string asyncPieName = string.Empty;
    try
    {
        var task = _pieMaker.GetDeliciousPieAsync();
        asyncPieName = await task;
    }
    catch (RottenFruitException e)
    {
        Debug.Write(e.Message);
    }  
    if (!string.IsNullOrEmpty(asyncPieName))
    {
        _pieName = asyncPieName;
        NotifyPropertyChanged(PieName);
    }
}

我想编写一个测试(我正在使用 RhinoMocks)来验证在该 getter 中抛出的异常不会让我得到带有腐烂水果的馅饼:

[TestClass]
public class FuzzyTest
{
    private FuzzyPickles _pickles;
    private IPie _pieMocker;  

    [TestInitialize]
    public void Setup()
    {
        _pieMocker = MockRepository.Mock<IPie>();
        _pickles = new FuzzyPickles(_pieMocker);
    }  

    [TestMethod]
    public void PieName_WhenGettingException_ShouldHandleExceptionGracefully()
    {
        _pieMocker.Stub(x => x.GetDeliciousPieAsync()).Throws(new RottenFruitException());  
        var pieName = _pickles.PieName;
        //What should I assert here ?
    }
}

现在这是我真正的问题。

删除 try/catch block 不会将异常抛回给 UT 运行器,因为我没有在 UT 中使用 await,因为它没有原型(prototype)化为异步任务并且 getter 不能异步,因此我不能等待或使用函数相反(或者我可以吗?)

那个 getter 绑定(bind)到 UI(即:我用它来在我的 UI 中显示信息,所以我不知道什么时候 - 如果有的话 - 它会被调用),这就是我做这个丑陋功能的原因调用 hack,并在其中使用 NotifyPropertyChanged(这里我们不要担心跨线程异常,这不是重点)

我不想使用隐藏代码(Windows Phone 8.1/Silverlight 项目)。

如果删除 try/catch block ,我该如何编写一个会失败的单元测试?我应该断言什么?

最佳答案

由于属性不兼容 async(这是 IMO 的明智设计选择),您可以采用 Stephan Clearys blog post 中提到的 IntializeXXXAsync 模式.

该模式的作用是让您调用负责创建值的初始化方法。如果失败,您可以默认返回到 default(T),在您的字符串情况下它只是 null,并对其断言:

public class FuzzyPickles : INotifyPropertyChanged
{
    public FuzzyPickles(IPie pieMaker)
    {
        _pieMaker = pieMaker;
    }     

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _pieName;
    public string PieName
    {
        get
        {
            return _pieName;
        }
        private set 
        {
            _pieName = value;
           OnPropertyChanged()
        }
    }  

    public async Task InitializePieAsync()
    {
        string asyncPieName = string.Empty;
        try
        {
            PieName = await _pieMaker.GetDeliciousPieAsync();
        }
        catch (RottenFruitException e)
        {
             Debug.Write(e.Message);
        }  
    }
}

现在初始化 FuzzyPickles,初始化并断言它不为空:

 [TestMethod]
 public async Task PieName_WhenGettingException_ShouldHandleExceptionGracefully()
 {
      _pieMocker.Stub(x => x.GetDeliciousPieAsync()).Throws(new RottenFruitException());  

      await  _pickles.InitializePieAsync();
      var pieName = _pickles.PieName;

      Assert.IsNotNull(pieName);
 }

关于c# - 单元测试在 try catch block 中调用异步操作的 getter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25751378/

相关文章:

c# - 如何根据数组中的值对对象列表进行排序?

.net - 从 GroupWise 中的电子邮件文件附件拖放到 .NET 应用程序

c# - 网站自动化的最佳方法?

python - Python 中的单元测试问题 "Imperative shell, functional core"

c# - 过滤连续数据,如何去除瞬变?

c# - 如何在运行时在 ASP.Net Core 中创建 url 重写?

c# - bool LINQ 问题

.net - 加密 connectionStrings 部分 - app.config 的实用程序

c# - 单元测试添加到 Zip/从 Zip 中提取

arrays - GO 中的测试列表