Skip to content

jwChung/Experimentalism

Repository files navigation

Stories in Ready Experimentalism appveyor

Experimentalism은 TDD에 도움을 줄 수 있는 라이브러리와 툴을 제공하는 것이 목적입니다.

Experimentalism의 모든 프로젝트(NuGet패키지)는 Semantic Versioning을 따릅니다.

Experimentalism의 프로젝트들은 NuGet에 등록이 되어있으므로, NuGet package manager 혹은 Package manager console을 통해 각 패키지들을 설치할 수 있습니다.

  • Experiment.Xunit:
    install from nugetdownloads
  • Experiment.Idioms:
    install from nugetdownloads

Experiment.Xunit

Experiment.Xunit란 Parameterized Test에 대한 auto data를 제공하기 위한 xUnit.net의 확장라이브러리입니다. 여기서 auto data란 테스트에 참여하는 객체 또는 값들이 anonymous 형태로 자동 생성된 것을 말합니다. 생성된 auto data는 테스트 메소드의 파라메타를 통해 제공되게 됩니다.

Parameterized test with auto data

이 기능이 테스트작성에 어떤 장점을 가져다주는지, 아래의 예제코드를 통해 살펴보도록 하겠습니다. 예를 들어, Person 클래스의 Say 메소드를 테스트한다면, 아마 우리는 SayTest와 같이 작성할 수 있을 것입니다.

public class Person
{
    private string name;
    
    public Person(string name)
	{
        this.name = name;
	}
    
    public string Name
    {
        get { return this.name; }
    }
    
    public string Say(string something)
    {
        return this.name + ": " + something;
    }
}

public class PersonTest
{
    [Fact]
    public void SayTest()
    {
        // Fixture setup
        var name = "Foo";
        var sut = new Person(name);
        var something = "Bar";
        var expected = name + ": " + something;
        
        // Exercise system
        var actual = sut.Say(something);
        
        // Verify outcome
        Assert.Equal(expected, actual);
    }
}

SayTest를 Experiment.Xunit를 이용하여 다시 작성해 보면 아래와 같은 테스트를 작성할 수 있습니다. sut, namesomething값을 파라메타로 넘겨받음으로써, 테스트 데이터 생성의 번거로움을 덜 수 있을 뿐 아니라, 테스트가 무엇을 테스트하는지 그 의도를 좀 더 명확히 보여줄 수 있게 됩니다.

public class PersonTest
{
    [Test]
    public void SayTest(Person sut, string something)
    {
        // Fixture setup
        var expected = sut.Name + ": " + something;
        
        // Exercise system
        var actual = sut.Say(something);
        
        // Verify outcome
        Assert.Equal(expected, actual);
    }
}

First class test with auto data

우리는 종종 아래와 같이 하나의 테스트에서 여러 테스트를 동시에 실행하는 것으로 Parameterized test 효과를 얻고자 합니다.

[Fact]
public void AddTest()
{
    AddTestCase(1, 2, 3);
    AddTestCase(2, 3, 5);
    AddTestCase(10, 2, 12);
}

public void AddTestCase(int a, int b, int expected)
{
    // Fixture setup
    var sut = new Calc();
    
    // Exercise system
    var actual = sut.Add(a, b);
    
    // Verify outcome
    Assert.Equal(expected, actual);
}

이러한 테스트를 xUnit Patterns에서는 Tabular Test라 하는데, 모든 테스트가 통과할 때는 문제가 없지만, 만약 하나라도 실패하게 된다면 우리는 그 실패가 3가지 중 어느 테스트에서 발생하였는지 쉽게 알아차릴 수 없게 됩니다(Eager Test, Defect Localization).

이 문제를 해결하기 위해서 Experiment.Xunit에서는 아래와 같이 xUnit.net의 DataAttribute를 사용하여 각각의 테스트를 분리하였습니다(Attribute Tabular Test). 이 경우 AddTest는 하나의 테스트가 아니라 arguments 별로 3개의 테스트로 작동하게 됩니다.

[Test]
[InlineData(1, 2, 3)]
[InlineData(2, 3, 5)]
[InlineData(10, 2, 12)]
public void AddTest(int a, int b, int expected)
{
    // Fixture setup
    var sut = new Calc();
    
    // Exercise system
    var actual = sut.Add(a, b);
    
    // Verify outcome
    Assert.Equal(expected, actual);
}

하지만 Attribute Tabular Test는 Tabular Test에서는 없는 문제점이 있는데, 그것은 type-safe 방식이 아니라는 점입니다. 그래서 Experiment에서는 Tabular Test와 Attribute Tabular Test의 장점만을 살릴 수 있는 First class test 방식을 지원합니다. First class test 방식에서는 Eager Test 문제를 해결함과 동시에 type-safe 방식을 지원하는 장점을 가집니다.

[Test]
public IEnumerable<ITestCase> AddTest()
{
	var testCases = new[]
	{
		new { X = 1, Y = 2, Z = 3 },
		new { X = 3, Y = 7, Z = 10 },
		new { X = 100, Y = 23, Z = 123 }
	};
	return TestCases.WithArgs(testCases).Create(
		c => Assert.Equal(c.Z, c.X + c.Y));
}

또한, First class test 방식은 아래와 같이 anonymous 값을 넘겨주는 auto data 기능도 제공합니다.

[Test]
public IEnumerable<ITestCase> AddTest()
{
	var testCases = new[]
	{
		new { X = 1, Y = 2, Z = 3 },
		new { X = 3, Y = 7, Z = 10 },
		new { X = 100, Y = 23, Z = 123 }
	};
	return TestCases.WithArgs(testCases).WithAuto<Calc>().Create(
		(c, sut) =>
		{
			var actual = sut.Add(c.X, c.Y);
			Assert.Equal(c.Z, actual);
		});
}

Credits

Inspiration

Experimentalism의 auto data 기능은 xUnit Test Patterns(by Gerard Meszaros)Anonymous Creation MethodParameterized Anonymous Creation Method에서 영감을 얻었으며, AutoFixtureAutoFixture.Xunit로부터 많은 영향을 받았습니다.

First class test 방식은 Bug squash의 First-class tests in MbUnit라는 글과 Exude에서 영감을 얻었습니다.

###Third-party libraries Experimentalism은 아래와 같은 Third-party libraries를 사용하고 있습니다. 아래의 각 라이브러리에서 언급되는 라이센스 전문은 LICENSE.txt 파일 또는 각 소스파일의 헤더형태로 제공되므로 이를 참고할 수 있습니다.

Icon image

Website: http://www.oxygen-icons.org
Copyright: Copyright (c) Oxygen Team
License: Creative Commons (Attribution-NonCommercial-NoDerivs 2.5 Generic)

Questions

Experimentalism에 대한 도움말이나 설명 문서가 많이 부족합니다. 따라서, 궁금증이나 문의가 있으시면 Issue list에 질문을 등록하실 수 있습니다.

Additional references

Experimentalism은 각 테스트 프로젝트에서 해당 프로젝트에 대한 시나리오 테스트(acceptance test)를 포함하고 있습니다. 이 시나리오 테스트들은 해당 프로젝트를 어떻게 이용하는지 간략히 잘 나타내고 있습니다. 아래 링크를 참고하세요.

Contributions

Coming together is a beginning; keeping together is progress; working together is success. – Henry Ford

관심이 있으신 누구나 Experimentalism에 참여하실 수 있습니다. 특히, TDD에 관심있거나 또는 배우고자하는 분들이 참여하시면 TDD에 관한 insight를 얻을 수 있을 것으로 생각됩니다. 참여방법은 CONTRIBUTING 문서를 통해서 확인하실 수 있습니다.

###New Contributor? Jump In! Experimentalism 오픈소스 참여에 익숙하지 않으신 분들은 Issue list에서 Jump in 라벨이 붙은 이슈를 주목하시기 바랍니다. Jump in 라벨은 다음과 같은 의미이며, _Experimentalism 오픈소스 참여를 독려하기 위한 장치_입니다.

  • 해당 이슈를 해결하는데 상대적으로 많은 시간을 할애하지 않아도 된다.
  • 상대적으로 독립적인 이슈이기 때문에 이해하기 쉽다.
  • 해당 이슈는 구현을 위한 핵심을 잘 지적하고 있다.
  • 필요 시 해당 이슈에 대한 설명을 요청할 수 있다.

About

Experimentalism은 TDD에 도움을 줄 수 있는 라이브러리와 툴을 제공하는 것이 목적입니다.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages