1
\$\begingroup\$

I have settled with this type of structuring of unit tests.

Basic idea is that there is a base test class for the tested class, and a subclass for every tested method. They use the mocks and everything from the base test class, the point being that the test would remain small, and you don't have to create everything in the test.

Idea for this came from Haacked http://haacked.com/archive/2012/01/02/structuring-unit-tests.aspx/

public class HomeControllerTest
{
    protected HomeController Controller;
    protected Mock<IUnitOfWork> UnitOfWork;
    protected Mock<IRepositoryOne<Entity>> Repository;
    protected Fixture Fixture;

    public HomeControllerTest()
    {
        UnitOfWork = new Mock<IUnitOfWork>();
        Repository = new Mock<IRepositoryOne<LoanRequirement>>();

        Controller = new HomeController(
            UnitOfWork.Object,
            Repository.Object);

        Fixture = new Fixture();
    }



    public class GetHomeMethod : HomeControllerTest
    {          
        [Fact]
        public void ReturnsEntityDataFromDatabase()
        {
            Repository.Setup(x => x.GetId(1)).Returns(new Entity());

            var result = Controller.GetOne(1) as OkNegotiatedContentResult<HomeModel>;
            Assert.NotNull(result);
            var model = result.Content;

            var entityToModel = Mapper.Map<HomeModel>(entity);
            Assert.Equal(model, entityToModel,HomeModel.HomeModelComparer);

        }
    }

    public class PostHomeMethod : HomeControllerTest
    {
        // Test the post method
    }

    public class PutHomeMethod : HomeControllerTest
    {
        // Test the put method
    }
}

I ask in general is there anything wrong about doing it like this, any dangers that I don't spot? Any comments are welcome. Main point for asking a question like this is to polish my unit tests, so they would be even more organized.

\$\endgroup\$
  • 1
    \$\begingroup\$ codereview.stackexchange.com/a/44879/7076 \$\endgroup\$ – palacsint Mar 21 '14 at 8:34
  • 1
    \$\begingroup\$ And then you'll end up with 100 classes that test one thing. What does this offer as an advantage over a simple setup method? \$\endgroup\$ – Jeroen Vannevel Mar 21 '14 at 12:47
  • \$\begingroup\$ What do you mean test only one thing? One class testes one method, usually there is more tests per method than one. This gives you more structured tests, like descried in the post. \$\endgroup\$ – TuomasK Mar 24 '14 at 6:56
2
\$\begingroup\$

There are a few major differences between what I understand from your code and what I understand from the post you mention.

Inheritance vs Nesting
Your code suggests that there is a subclass for each tested method, although the post talks about nested classes:

The structure has a test class per class being tested. That’s not so unusual. But what was unusual to me was that he had a nested class for each method being tested.

Class per test vs Class per Method
Also, your code example implies that each class contains a single test, which loses all meaning for the class. The post talks about a class per method tested, which mean that it may contain more than one test, but all tests are relevant to the same method.

using Xunit;

public class TitleizerFacts
{
    public class TheTitleizerMethod
    {
        [Fact]
        public void ReturnsDefaultTitleForNullName()
        {
            // Test code
        }

        [Fact]
        public void AppendsTitleToName()
        {
            // Test code
        }
    }

This kind of structure is very similar to how an RSpec test would be structured, having multiple layers of describe blocks for different scopes - class, method, feature...

describe HomeController do

  let (:fixture) { double('fixture') }

  before(:each) do
    # something before each test
  end

  describe '#get_home' do

    before(:each) do
      expect(repository).to receive(:get_id).with(1).and_return(entity)
    end

    let(:result) { subject.GetOne(1) }

    it 'returns result' do
       expect(result).to_not be_nil
    end 

    it 'returns entity data from database' do
       expect(result.content).to eq entity
     end
  end
end
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.