• 10 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 8/6/19

Fix that bug!

We’re still looking for the source of the bug that caused the ArgumentNullException when the VerifyAddTask unit test is executed in the file T_TodoModel.cs. It’s time to conclude this bug hunt!

Finding the cause of the bug

By managing exceptions and breakpoints, we’ve gotten as far as the code in the InternalAddTask method, and are attempting to find where the exception is coming from:

Internaladdtask implementation
Internaladdtask implementation

Seeing this code, we're going to have to go back through InternalAddTask using Step Into (F11).  If the test of the first line fails, it will throw an InvalidOperationException  – but it is not the ArgumentNullException that is detected.

It’s possible that the exception is being thrown within the test itself, when inserting into the _tasks field (which is an instance of List<TodoTask>).

How can we remove any doubt without executing or going down into GetTask?

Check that the received task, and the name sent as a parameter, aren't null: the GetTask parameters are not null.

However, by hovering the mouse over the _task field, it seems that its value is null: the name entered as a parameter is not.

_task is null
_task is null

So let’s start from this theory and go into the GetTask method using Step Into (F11):

_task really is null
_task really is null

The editor indicates that _tasks has a value of null as we saw in the calling method. It’s obvious that the call to FirstOrDefault is going to fail because the list on which this method is going to operate will be null: now we know why the ArgumentNullException is going to be thrown! ;)

Fixing the problem

Seeing the TodoModel class implemented (no constructor or _tasks field explicitly initialized), it looks as though the _tasks field wasn't initialized. So we need to add the following code:

Remember to initialize _task
Remember to initialize _task

Remember: we need to ensure that the fix solves the initial problem. To do this, we rerun the unit test and check that it goes through okay. Unfortunately, this is not the case!

VerifyAddTest fails again
VerifyAddTest fails again

This time, we get an InvalidOperationException exception type. The message indicates that it is not possible to insert the sleep task a second time.

A bug is not fixed until it passes all the tests following a correction. As that is not the case here, we must carry on with our investigation.

Starting a new investigation

How should we start this new investigation?

One way is to look at the code where the exception is thrown, and insert a breakpoint; not on the line, but on the throw using a right-click or the keyboard shortcut F9:

Setting a breakpoint on the throw
Setting a breakpoint on the throw

The debugger will halt execution just before the exception is thrown.

As mentioned in the previous chapter, you might also want to put a breakpoint on the call to CreateTask in the foreach loop:

Defining a condition on the breakpoint
Defining a condition on the breakpoint

You can also define a Hit Count conditional breakpoint to pause before executing the fourth iteration (i.e., before the second task with the name sleep added):

Defining a condition over 4 iterations
Defining a condition over four iterations

When we rerun the unit test, it throws an exception if there is a task with the same name, as you would expect. We need to decide if we should retain this function, modify the unit test, or add another to make the expected behavior official.

Let's recap!

As you can see, an investigation may require several iterations of the search for a bug. Most of the time there are several possible outcomes. However, I suggest that you add unit tests, which makes the behavior of the tested components easier to follow!

The next part of this course will give you a new way of viewing and modifying data that is being manipulated by code. This will help you be more efficient and able to understand the code you maintain - even if you didn't write it. 😎

Example of certificate of achievement
Example of certificate of achievement