Unit Testing a receiver that calls an async operation in a try catch block

I have the following piece of code:

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);
    }
}

      

And I want to write a test (I am using RhinoMocks) to make sure that the exception thrown in this receiver will not give me rotten fruit tarts:

[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 ?
    }
}

      

Now here's my real problem.

Removing the try / catch block does not return an exception for the UT runner because I am not using it in UT since it is not prototyped as async. Task and getters cannot be asynchronous, so I cannot wait or use a function (Or can I?)

This getter is user interface bound (ie: I use it to display information in my user interface, so I don't know when - if ever - it will be called), which is why I make this ugly function call hack and use NotifyPropertyChanged in it (don't worry about cross-exceptions here, it doesn't)

I don't want to use hack code (Windows Phone 8.1 / Silverlight project).

How can I write a Unit Test that works if I remove the try / catch block? What should I argue about?

+3


source to share


2 answers


Since the properties are not compatible with async

(which is a wise design choice IMO), you can grab the template IntializeXXXAsync

mentioned in Stephan Clearys' blog post .

What the template does is you call the initialization method, which is responsible for creating the values. If it fails, you can default back to default(T)

which in your case the lines are simple null

and assert on it:

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);
        }  
    }
}

      



Now you initialize FuzzyPickles

, initialize and assert that it is not null:

 [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);
 }

      

+3


source


Create a new method GetPieNameAsync

that returns Task

. This method can be easily verified using await

. If, for some reason, you also need a fire-and-forget method, use it for invocation only GetPieNameAsync()

.



private async void GetPieName()
{
    await GetPieNameAsync();
}

private async Task GetPieNameAsync()
{
    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);
    }
}

      

0


source







All Articles