0

I want to write Test cases for C# code that triggers events or displays a form to user for input e.g.:

private void CreateRecord_Click(object sender, EventArgs e)
{
    try
    {
        this.InitiateRecording();
    }
    catch (BubbleUiException ex)
    {
        objLog.Error(TextRes.IDC_EShuttleError, ex);
        MessageBox.Show(
            ex.Message,
            TextRes.IDC_EShuttleError,
            MessageBoxButtons.OK,
            MessageBoxIcon.Error);
     }
     catch (Exception ex)
     {
         objLog.Error("Error occurred", ex);
         MessageBox.Show(
             ex.Message,
             TextRes.IDC_Error,
             MessageBoxButtons.OK,
             MessageBoxIcon.Error);
     }
 }

How to write Unit tests for these kind of code using Mbunit?

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
priya
  • 852
  • 18
  • 39

2 Answers2

3

The "purist" answer is that since it's a private method, it should not be unit tested as it's an implementation detail. You should aim to test public APIs only.

As it is an event handler, you may still want to test it for various reasons. As currently written though, this will be hard to do. The fact that you have a

this.InitiateRecording();

line suggests you haven't properly implemented separation of concerns. Your class for handling events also seems to contain code for handling recording. Secondly, you have hard-coded calls to MessageBox.Show, which will make testing hard as your tests cannot be run in an automatic, stand-alone fashion.

I'd recommend therefore:

  1. Refactor the recording functionality out into a separate class, which can be unit tested.
  2. Inject the MessageBox.Show method into that class, so that it can be stubbed during testing.
  3. Do not test CreateRecord_Click() as it will simply call a method in your new class.
David Arno
  • 42,717
  • 16
  • 86
  • 131
  • Thanks a lot david for your suggestion. I hope Testing only Initiate Recording for various Exception will suffice the Testing without bothering whether event is raised or not properly. – priya Oct 07 '13 at 12:34
  • 1
    log could be injected as well. as – Tony Hopkinson Oct 07 '13 at 12:34
  • @Tony, indeed that would be a further improvement. – David Arno Oct 07 '13 at 12:35
  • @Tony : Log could be injected as well , does that mean logging inside Unit Testing?? or something else?? – priya Oct 07 '13 at 13:00
  • @priya it means you can replace your real logger with a fake one while you are testing your method. So you can test your code without worrying about what logger is or isn't doing. – Sam Leach Oct 07 '13 at 13:09
  • As @SamLeach says, you could throw a mock or a stub at it. Our code the logs are considered customer artifacts, well for the cleverer ones anyway. Certainly our Support guys have an interest, so I have a common interface and my test implementation exposes a string of all the messages that have been written during the test, then I can do some shoulds on that. – Tony Hopkinson Oct 07 '13 at 20:16
0

Test:

  1. this.InitiateRecording() is called
  2. Force a BubbleUiException when this.InitiateRecording() is called
  3. Force a Exception that is not BubbleUiException when this.InitiateRecording() is called
  4. Wrap MessageBox.Show so you can test that it prints what you expect when the exceptions are thrown.
  5. Test objLog.Error is called.

You can assume that your click event works (that the method is called when the control is clicked) as Microsoft have already tested this.

Sam Leach
  • 12,746
  • 9
  • 45
  • 73
  • 2
    What you are suggesting here is that a test be written that tests CreateRecord_Click() functions as currently written. This is both bad practice (one should test behaviour, not implementation) and will lead to the creation of a highly brittle test, which will break as soon as the implementation changes. – David Arno Oct 07 '13 at 13:10
  • @DavidArno you're very right, OP's code is not testable in it's current form. I have suggested how he test it in it's current form, which is what he asked. – Sam Leach Oct 07 '13 at 13:39