kseen
kseen

Reputation: 397

How to find places in code that must be covered with unit tests

I know it's not so good to write tests after you actually wrote code. I'm unit-testing newbie and feel that unit-testing may deliver many good advantages so I obsessed with an idea to cover as much as possible.

For instance, let we have this code:

public class ProjectsPresenter : IProjectsViewObserver
{
    private readonly IProjectsView _view;
    private readonly IProjectsRepository _repository;

    public ProjectsPresenter(IProjectsRepository repository, IProjectsView view)
    {
        _view = view;
        _repository = repository;
        Start();
    }

    public void Start()
    {
        _view.projects = _repository.FetchAll();
        _view.AttachPresenter(this);
    }

}

So looking on code above could you answer me what tests typically I should write on that piece of the code above?

I'm rolling on write tests on constructor to make sure that repository's FetchAll was called and on the view site AttachPresenter is called.


POST EDIT

Here is a my view interface:

public interface IProjectsView
{
    List<Project> projects { set; }
    Project project { set; }

    void AttachPresenter(IProjectsViewObserver projectsPresenter);
}

Here is a view:

public partial class ProjectsForm : DockContent, IProjectsView
{
    private IProjectsViewObserver _presenter;
    public ProjectsForm()
    {
        InitializeComponent();
    }

    public Project project
    {
        set
        {
            listBoxProjects.SelectedItem = value;
        }
    }

    public List<Project> projects
    {
        set
        {
            listBoxProjects.Items.Clear();   
            if ((value != null) && (value.Count() > 0))
                listBoxProjects.Items.AddRange(value.ToArray());
        }
    }

    public void AttachPresenter(IProjectsViewObserver projectsPresenter)
    {
        if (projectsPresenter == null)
            throw new ArgumentNullException("projectsPresenter");

        _presenter = projectsPresenter;
    }

    private void listBoxProjects_SelectedValueChanged(object sender, EventArgs e)
    {
        if (_presenter != null)
            _presenter.SelectedProjectChanged((Project)listBoxProjects.SelectedItem);
    }
}

POST EDIT #2

This is how I test interaction with repository. Is everything allright?

    [Test]
    public void ProjectsPresenter_RegularProjectsProcessing_ViewProjectsAreSetCorrectly()
    {
        // Arrange
        MockRepository mocks = new MockRepository();
        var view = mocks.StrictMock<IProjectsView>();
        var repository = mocks.StrictMock<IProjectsRepository>();
        List<Project> projList = new List<Project> {
            new Project { ID = 1, Name = "test1", CreateTimestamp = DateTime.Now },
            new Project { ID = 2, Name = "test2", CreateTimestamp = DateTime.Now }
        };
        Expect.Call(repository.FetchAll()).Return(projList);
        Expect.Call(view.projects = projList);
        Expect.Call(delegate { view.AttachPresenter(null); }).IgnoreArguments();
        mocks.ReplayAll();
        // Act
        ProjectsPresenter presenter = new ProjectsPresenter(repository, view);
        // Assert
        mocks.VerifyAll();            
    }

Upvotes: 3

Views: 330

Answers (5)

Rober
Rober

Reputation: 85

The purpose of writing tests before writing production code is first and foremost to put you (the developer) in the mind-set of "how will i know when my code works?" When your development is focused on what the result of what working code will look like and not the code itself you are focused on the actual business value obtained by your code and not extraneous concerns (millions of man hours have been spent building and maintaining features users never asked for, wanted, or needed). When you do this you are doing "test driven development".

If you are doing pure TDD the answer is 100% code coverage. That is you do not write a single line of production code that is not already covered by a line of unit test code.

In Visual Studio if you go to Test->Analyze Code Coverage it will show you all of the lines of code that you do not have covered.

Practically speaking its not always feasible to enforce 100% code coverage. Also there are some lines of code that are much more important then others. Determining which depends once again on the business value provided by each line and the consequence of that line failing. Some lines (like logging) may have a smaller consequence then others.

Upvotes: 0

k.m
k.m

Reputation: 31444

I know it's not so good to write tests after you actually wrote code

It's better than not writing tests at all.

Your method works with two external components and that interaction should be verified (in addition to mentioned arguments validation). Checking whether FetchAll was called gives you no value (or checking it returns something - this belongs to ProjectsRepository tests itself) - you want to check that view's projects are set (which will indirectly check whether FetchAll was called). Tests you need are:

  • verify that view projects are set to expected value
  • verify that presenter is attached
  • validate input arguments

Edit: example of how you would test first case (projects are set)

// "RegularProcessing" in test name feels a bit forced;
// in such cases, you can simply skip 'conditions' part of test name
public void ProjectsPresenter_SetsViewProjectsCorrectly()
{
    var view = MockRepository.GenerateMock<IProjectView>();
    var repository = MockRepository.GenerateMock<IProjectsRepository>();
    // Don't even need content;
    // reference comparison will be enough
    List<Project> projects = new List<Project>();
    // We use repository in stub mode;
    // it will simply provide data and that's all
    repository.Stub(r => r.FetchAll()).Return(projects);
    view.Expect(v => v.projects = projects);

    ProjectsPresenter presenter = new ProjectsPresenter(repository, view);

    view.VerifyAllExpecations();
}

In second case, you'll set expectations on view that its AttachPresenter is called with valid object:

public void ProjectsPresenter_AttachesPresenterToView()
{
    // Arrange
    var view = MockRepository.GenerateMock<IProjectView>();
    view.Expect(v => v.AttachPresenter(Arg<IProjectsViewObserver>.Is.Anything));
    var repository = MockRepository.GenerateMock<IProjectsRepository>();

    // Act
    var presenter = new ProjectsPresenter(repository, view);

    // Assert
    view.VerifyAllExpectations();
}

Upvotes: 2

Ian Gilroy
Ian Gilroy

Reputation: 2041

Pex is an interesting tool that's worth checking out. It can generate suites of unit tests with high code coverage: http://research.microsoft.com/en-us/projects/pex/. It doesn't replace your own knowledge of your code - and which test scenarios are more important to you than others - but it's a nice addition to that.

Upvotes: 0

Lukasz Madon
Lukasz Madon

Reputation: 14994

I would add tests for exception e.g. ArgumentException, corner cases and usual ones of FetchAll().

PS. Does start have to be public?

Upvotes: 0

Tigran
Tigran

Reputation: 62248

I would add simple tests at start , like:

  • null reference checks

  • FetchAll() returns any value

Do not add a lot of test code at first time, but refine them after as your dev code mutates.

Upvotes: 0

Related Questions