반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

SetUpFixture tutorial -FitLibrary-

2013. 8. 17. 00:18 | Posted by 솔웅


반응형

FitLibrary

FitLibrary는 fixture의 third-party set으로 시작했습니다. 하지만 이 기능이 하도 유용해서 지금은 standard test 타입의 하나로 간주되고 있습니다. 자바버전에서는 아직 별도의 라이브러리로 관리됩니다.






SetUpFixture


SetUpFixture는 아무것도 테스트하지 않고 싶을 때 ColumnFixture를 완벽하게 대신할 수 있는 fixture 입니다. 다른 fixture들을 위한 stage를 준비하기 위해서 사용하는 것이죠. 예를 들어 데이터메이스의 테이블에 row들을 insert하거나 이후의 테스트들에서 사용될 domain object들을 생성할 때 이 SetUpFixture를 사용하실 수 있습니다.




Table Format

첫번째 줄은 fixture 클래스 이름이 됩니다. 두번째줄은 객체의 프로퍼티 이름들 입니다. 이후의 모든 줄들은 프로퍼티값들을 가지게 됩니다. 이 SetUpFixture table 에는 output cell 이 없습니다. 모두 input에만 사용이 됩니다.

!|SetUpFixtureTest|
|player|post code|balance|
|John Smith|SW4 66Z|10.00|
|Michael Jordan|NE1 8AT|12.00|



Fixture class

이 fixture 클래스는 fitlibrary.SetUpFexture를 extend 하고 single method를 정의합니다. 메소드 이름은 연결된 테이블에 있는 프로퍼티 이름들과 같아야 합니다. (두개의 분리된 단어를 표현하려면 CamelCase capitalisation을 사용하시면 됩니다.) 이 메소드는 테이블의 각 컬럼들에 대해 하나씩의 argument를 가지게 됩니다.



Java Source Code

package info.fitnesse.fixturegallery;

import info.fitnesse.fixturegallery.domain.Player;

import java.util.ArrayList;
import java.util.List;

import fitlibrary.SetUpFixture;

public class SetUpFixtureTest extends SetUpFixture{
	public SetUpFixtureTest() {
		 Player.players.clear();
	}
	public void playerPostCodeBalance(String name, String postCode, double balance){
	 Player.addPlayer(name, postCode, balance) ;
 }
}

.NET Source Code

namespace info.fitnesse.fixturegallery
{
    public class SetUpFixtureTest : fitlibrary.SetUpFixture
    {
        public SetUpFixtureTest()
        {
            Player.players.Clear();
        }
        public void PlayerPostcodeBalance(string player, string postCode, decimal balance)
        {
            Player p = new Player();
            p.Name = player;
            p.PostCode = postCode;
            p.Balance = balance;
            Player.players.Add(p);
        }
       }
}

Python Source Code

from fitLib.SetUpFixture import SetUpFixture
from info.fitnesse.fixturegallery.domain.Player import Player

class SetUpFixtureTest(SetUpFixture):
    _typeDict = {}

    def __init__(self):
        Player.players = []

    # JAVA: void playerPostCodeBalance(String name, String postCode, double balance){
    _typeDict["playerPostCodeBalance.types"] = [ None, "String", "String", "Float" ]
    def playerPostCodeBalance(self, name, postCode, balance):
        Player.addPlayer(name, postCode, balance)




Notes

메소드 이름은 길어 질 수도 있습니다. 이런 긴 메소드 이름을 타이핑하다보면 에러가 발생할 수가 있습니다. 매뉴얼로 타이핑하는 대신 테이블을 작성하고 test를 run 하세요. 그러면 처음에는 fail 하게 될 겁니다.



Usage

SetUpFixture는 domain object들을 신속하게 initialise 하고자 할 때 사용하실 수 있습니다. 데이터베이스 테이블을 준비하거나 서로 다른 argument들을 pass 해서 메소드를 여러번 실행시키고자 할 때 사용하기 좋습니다.

result나 error verification이 중요할 때 이 SetUpFixture를 사용하지는 마세요. 그럴때는 ColumnFixture를 사용하시거나 CalculateFixture를 사용하시는게 더 좋습니다.

반응형

Import Fixture Tutorial & Summery (FitNesse)

2013. 8. 17. 00:10 | Posted by 솔웅


반응형

Import

Import fixture는 FitNesse에게 fixture class들에 대해 어디를 봐야될지 얘기해야 할 때 사용될 수 있다. namespace나 package 를 import 하고 나면 여러분은 더 이상 해당 fixture 클래스의 전체 이름을 다 쓰지 않아도 됩니다. 그러면 table을 좀 더 가독성 있도록 만들 수 있게 되겠죠.



Table Form

테이블의 첫번째 줄은 import 가 되어야 합니다. 그 다음 줄들은 import 할 namespace와 package들의 리스트들입니다. 한 셀당 한 row 입니다.

|Import|
|info.fitnesse.fixturegallery|




Notes

.NET 버전은 대소분자 구분을 하지 않습니다. 그러니까 첫번째 줄은 import를 쓰던 Import 를 사용하던 상관 없습니다. 자바버전은 대소분자 구분을 합니다. 그러니 대소분자 구분을 확실히 하셔서 사용하셔야 합니다.
flow mode에서는 Import 테이블이 flow calss name을 initial 한 이후에 와야 된다는 것을 잊지 마세요. 그렇지 않으면 folw mode가 제대로 작동하지 않을 겁니다. (Flow Mode links)



Usage

test page를 좀 더 가독성 있게 만들기 위해서 이 Import fixture를 사용합니다. test suite의 SetUp 페이지에 이 테이블을 넣으실 수 있습니다.



SummeryFixture

SummaryFixture는 페이지의 extra 데이터를 표시하기 위해 사용합니다. fit.SummaryFixture table을 페이지 아래에 추가히세요. 그러면 results 에 3줄의 테이블이 추가 될 겁니다. 그리고 여기에 페이지의 standard counts가 주어질 겁니다. (right,wrong, ignore, exceptions) 또한 date와 fixture가 실행된 시간도 표시됩니다. 이 기능은 꼭 필요한 것은 아닙니다. 하지만 build report가 필요할 때 사용하실 수 있겠죠. 개별 페이지의 실행시간 같은 것을 뽑을 때 말이죠.

==> 여기까지는 Fixture의 Basic 입니다. 이 외에 FitLibrary Fixture의 Fixture 들이 있는데 여기에 대해서는 다음 글에서 계속 이어가겠습니다.


참고로 아래 Basic Fixture에 종류와 원본 링크를 넣겠습니다.

원문에 관심 있으신 분은 링크를 따라 가시면 보실 수 있습니다.





Basic Fixtures


ColumnFixture
ActionFixture
RowFixture
TableFixture
Import
SummaryFixture

반응형

TableFixture Tutorial (FitNesse)

2013. 8. 14. 22:02 | Posted by 솔웅


반응형

TableFixture


TableFixture 는 FitNesse package의 additional class 입니다. (core FIT fixture set 에는 존재하지 않는 겁니다.  FitNesse와 같은 라이브러리의 한 부분으로서 다뤄지고 있습니다.). 반복적인 구조를 가지고 있지 않은 free-form table들을 실행시킬 때 사용합니다.

Table Format


TableFixture로 어떤 포맷인지 어떤 셀을 테스트할 것이지 등을 정하실 수 있습니다. 제한점이 있다면 첫번째 줄은 fixture의 클래스 이름이어야 한다는 것 뿐입니다. 나머지는 여러분 마음대로 하셔도 됩니다. 기존의 인보이스나 reports 혹은 document들을 FitNesse test로 바꿀 때 사용하실 수 있습니다. 아래 예제들은 Test Driven .NET Development with FitNesse 에서 가져온 것입니다. 인보이스를 세금계산으로 verify 하겠습니다.

!|TableFixtureTest|
|Item|Product code|Price|
|Pragmatic Programmer|B978-0201616224|34.03|
|Sony RDR-GX330|ERDR-GX330|94.80|
|Test Driven Development By Example|B978-0321146533|32.39|
|Net Total||161.22|
|Tax (10% on applicable items)||9.48|
|Total||170.70|


Fixture class


이 fixture class를 사용하려면  fitnesse.fixtures를 extend 해야 합니다. doStaticTable(int rows) method를 override 합니다. 그 메소드에서 getText(row, column)으로 관계된 cell들의 내용들을 추려내서 table을 process 하는 겁니다. test cell들을 right(row,column)로 correct 하거나 wrong(row,column,actualValue)로 incorrect 하도록 test cell들을 mark 하실 수 있습니다.

아래 예제는 아래에서부터 두번째 줄의 세번째 cell에 있는 값고 매치되는 인보이스로부터 total tax를 verify 하는 에제입니다.

Java Source Code

package info.fitnesse.fixturegallery;

import info.fitnesse.fixturegallery.domain.TaxCalculator;
import fitnesse.fixtures.TableFixture;

public class TableFixtureTest extends TableFixture{
	protected void doStaticTable(int rows) {
		 TaxCalculator tc=new TaxCalculator();
	      double totaltax = 0;

	      for (int row = 1; row < rows - 3; row++)
	      {
	        totaltax += tc.GetTax(getText(row, 1),
	          Double.parseDouble(getText(row, 2)));
	      }
	      double taxintable = Double.parseDouble(getText(rows - 2, 2));
	      if (taxintable == totaltax)
	        right(rows - 2, 2);
	      else
	        wrong(rows - 2, 2,String.valueOf(totaltax));
	    }
}


.NET Source Code

using System;
using System.Collections.Generic;
using System.Text;

namespace info.fitnesse.fixturegallery
{
    public class TableFixtureTest : global::fitnesse.fixtures.TableFixture
    {
        protected override void DoStaticTable(int rows)
        {
            TaxCalculator tc = new TaxCalculator();
            decimal totaltax = 0;
            for (int row = 1; row < rows - 3; row++)
            {
                totaltax += tc.GetTax(GetString(row, 1),
                  Decimal.Parse(GetString(row, 2)));
            }
            decimal taxintable = Decimal.Parse(GetString(rows - 2, 2));
            if (taxintable == totaltax)
                Right(rows - 2, 2);
            else
                Wrong(rows - 2, 2, totaltax.ToString());
        }
    }

}

Python Source Code

from info.fitnesse.fixturegallery.domain.TaxCalculator import TaxCalculator
from fitnesse.fixtures.TableFixture import TableFixture

class TableFixtureTest(TableFixture):
    def doStaticTable(self, rows):
        tc = TaxCalculator()
        totalTax = 0.0

        for row in range(1, rows - 3):
            totalTax += tc.getTax(self.getText(row, 1),
                                  float(self.getText(row, 2)))

        taxinTable = float(self.getText(rows - 2, 2))
        if taxinTable == totalTax:
            self.right(self.getCell(rows - 2, 2))
        else:
            self.wrong(self.getCell(rows - 2, 2), str(totalTax))

Notes


정수형으로 변환된 cell 값을 retrieve 할 때 getInt 를 사용하시면 됩니다.

Usage


다른 fixture type으로는 구현하기 힘든 특정 business-specific table 포맷에 대해서 테스트 하기를 원하신다면 이 TableFixture를 사용하시는게 좋습니다. HTML table로 export 될 수 있는 문서를 가지고 있다면 더 쉽게 테스트를 구현하실 수 잇습니다. 그 HTML을 FitNesse로 곧바로 붙여넣기 하면 될 테니까요.


반응형

RowFixture Tutorial (Fitnesse)

2013. 8. 14. 21:43 | Posted by 솔웅


반응형

RowFixture



RowFixture 는 객체들의 다이나믹한 리스트를 테스트합니다. Expected list (FitNesse Table)와 실제 결과 리스트 (fixture code로부터 도출된)를 비교하게 됩니다. 그리고 추가되고나 missing 된 아이템들을 report 하게 되는 거죠.

Table Format


테이블의 첫번째 줄은 fixture class 이름 입니다. 두번째 줄은 리스트 내의 객체들 구조를 나타내구요. (verify 하기를 원하는 프로퍼티들이나 메소드들이 되겠죠.). 그 이후에 나오는 줄들은 배열에 있는 expected objects 들입니다.

!include -seamless SetUpFixture

!|RowFixtureTest|
|name|post code|
|John Smith|SW4 66Z|
|Michael Jordan|NE1 8AT|


Fixture class


이 fixture class는 fit.RowFixture 를 extend 해야 하고 아래 두개의 메소드들을 오버라이드 해야 합니다.

  • getTargetClass — returns the Type or Class object representing the type of objects contained in the array.
  • query — returns the actual array of objects to be verified.
# section Java Source Code

Java Source Code

package info.fitnesse.fixturegallery;

import info.fitnesse.fixturegallery.domain.Player;
import fit.RowFixture;

public class RowFixtureTest extends RowFixture{
	public Class getTargetClass() {
		return Player.class;
	}
	public Object[] query() throws Exception {
			return Player.players.toArray();
	}
}

.NET Source Code

using System;
using System.Collections.Generic;
using System.Text;

namespace info.fitnesse.fixturegallery
{
    public class RowFixtureTest: fit.RowFixture
    {
        public override Type GetTargetClass()
        {
            return typeof(Player);
        }
        public override object[] Query()
        {
            return Player.players.ToArray();
        }
    }
}

Python Source Code

from fit.RowFixture import RowFixture
from info.fitnesse.fixturegallery.domain.Player import Player

class RowFixtureTest(RowFixture):
    def getTargetClass(self):
        return Player

    def query(self):
        return list(Player.players) #< Return copy of players

Notes


그 객체가 identity (primary key 같은)의 한 부분이 되는 프로퍼티들을 가지고 있다면 그 프로퍼티들의 리스트들은 부가 정보 리스트들의 왼쪽에 놓여지게 됩니다. 이렇게 하면 error report를 보기가 훨씬 쉬워집니다. Figure 1을 봐 보세요. 두 클래스 모두 에러는 같습니다. 하지만 그 컬럼의 순서로 인해 하나는 주요 항목에 대한 에러를 알아보기가 쉽도록 보여주고 다른 하나는 모든 줄이 missing 되 버리게 됩니다.


Figure 1: RowFixture maps rows to objects from left to right



query method 다른 추가적인 argument들을 pass 하도록 허용하지 않습니다. 좀 더 자세한 정보를 보시려면 Fixture Arguments를 보세요.

리스트의 element들의 순서는 상호 의존적이지 않습니다. RowFixture 는 이를 무시할 겁니다.

Usage


객체들의 리스트를 verify 하려면 Use RowFixture 를 사용해서 테스트 하세요. 혹은 리스트 내의 모든 리스트들에 method를 만들어서 실행하셔도 됩니다. (이러면 번거롭겠죠?)


element 의 순서가 중요할 때는 이 RowFixture를 사용하지 마세요. 대신 ArrayFixture를 사용하세요.


반응형

ActionFixture Tutorial (Fitnesse)

2013. 8. 14. 10:23 | Posted by 솔웅


반응형

ActionFixture


ActionFixture 는 기본적으로 반복적인 경우가 아니라 workflow-style test를 위한 겁니다. 다른 fixture들을 automate 하기 위해 UI metaphor 를 사용합니다.



Table Format


ActionFixture table의 첫번째 줄(row)은 fixture class를 initialise합니다. 이 경우에는 다른 custom subclass가 아니라  ActionFixture 그 자체가 되겠습니다. 다른 모든 row들은 command cell 로 시작됩니다. 그리고 이 후의 cell 들에는 command argument들이 이어서 들어옵니다. 어떤 row들은 두개를 어떤 줄들은 3개의 셀들을 가집니다.

두번째 줄은 주로 start command 로 사용됩니다. 하나의 argument를 필요로 하죠. 그리고 automate 하는 실제 fixture의 클래스 이름이 옵니다. 그 다음에 테스트를 하기 위해 다른 command들을 사용하실 수 있습니다.

  • check — executes a method and verifies its value.
  • press — executes a void method without testing anything.
  • enter — executes a method and passes an argument to it.


여러분은 ActionFixture 를 UI form들을 populate 하고 method들과 연결된 버튼을 click 하기 위한 automation tool로 생각하셔도 됩니다.


!|ActionFixture|
|start|ActionFixtureTest|
|enter|firstPart|Hello|
|enter|secondPart|World|
|press|join|
|check|together|Hello, World|

(이 이미지는 source code와 다른 화면 입니다.)


Fixture class


다른 Fixture와 ActionFixture 가 다른 점은 따로 ActionFixture 를 extend 하지 않아도 된다는 겁니다. ActionFixture 대신에 fit.Fixture class를 곧바로 extend 합니다.



Java Source Code

package info.fitnesse.fixturegallery;

public class ActionFixtureTest extends fit.Fixture{
	private String first, second, both;
	public void firstPart(String s){
		first=s;
	}
	public void  secondPart(String s){
		second=s;
	}
	public void join(){
		both=first+ ", "+second;
	}
	public String together(){
		return both;
	}
}

.NET Source Code

using System;

namespace info.fitnesse.fixturegallery
{
	public class ActionFixtureTest: fit.Fixture
	 {
		public String firstPart, secondPart, together;
		public void join()
		{
			together=firstPart+ ", "+secondPart;
		}
	}
}

Python Source Code

from fit.Fixture import Fixture

class ActionFixtureTest(Fixture):
    _typeDict = {}

    def __init__(self):
        Fixture.__init__(self)
        self.__first  = ""    #< Private attributes (Python convention).
        self.__second = ""
        self.__both   = ""

    # JAVA: void firstPart(String s)
    _typeDict["firstPart"] = "String"
    def firstPart(self, s):
        self.__first = s

    # JAVA: void  secondPart(String s)
    _typeDict["secondPart"] = "String"
    def secondPart(self, s):
        self.__second = s

    # JAVA: void join()
    _typeDict["join"] = "Default"      #< AUTO-DETECT: None = void
    def join(self):
        self.__both = "%s, %s" % (self.__first, self.__second)

    # JAVA: String together()
    _typeDict["together"] = "String"
    def together(self):
        return self.__both


Notes

In the Java version, ActionFixture only works on methods. in the .NET version, enter and check can get and set fields and properties as well.
자바 버전에서는 ActionFixture 가 오직 method에 대해서만 적용됩니다. .NET 버전에서는 enter 와 check 이 필드와 프로퍼티들을 get,set 할 수 있습니다.



Usage


여러분은 ActionFixture 를 UI-style verification들을 처리하기 위해 사용하실 수 있습니다.

일반적으로 ActionFixtureDoFixture (see DoFixture )에 의해 replace 됩니다. 요즘은 이 ActionFixture를 써야 되는 경우가 한정돼 있죠. DoFixture 도 workflow-style 테스트를 할 수 있도록 기능을 제공 합니다. 사실 훨씬 더 쉽게 사용할 수 있도록 해 줍니다. DoFixture 가 fixture와 FitNesse table 모두 더 적은 코딩을 할 수 있도록 해 주고요.  DoFixture는 direct domain object wrapping 도 지원합니다.


반응형

ColumnFixture Tutorial (Fitnesse)

2013. 8. 12. 10:38 | Posted by 솔웅


반응형

Fitnesse에 대해서 공부하려고 하는데 검색을 해 봐도 별로 맘에 드는 블로그를 못 찾겠네요. 그래서 Fitnesse 홈페이지에 있는 Tutorial을 한번 쪽 훑어 보겠습니다.

기초적인 Research는 된 것 같아서 Fixture에 대한 부분을 살펴 봅니다.

여기로 가시면 Tutorial 원문을 보실 수 있습니다.

ColumnFixture


ColumnFixture 는 table 의 컬럼들을 곧바로 fixture class의 프로퍼티와 메소드 그리고 필드들로 매핑합니다. 이는 같은 테스트가 다양한 입력 argument들에 대해 반복적으로 사용되어야 할 때 반복적으로 사용되는 변수들을 만들 때 아주 유용합니다.

Table Format


테이블의 첫번째 줄(row)는 테스트 클래스의 이름입니다. 두번째 row의 컬럼 이름들은 이 컬럼과 관계된 필드나 메소드를 가리킵니다. Output 값들은 반드시 필드나 메소드 이름 다음에 ? 나 ()를 를 붙여야 합니다. 그 이후의 row들은 input argument들과 기대되는 결과값(output arguments)들의 combination list들 입니다.

!|info.fitnesse.fixturegallery.ColumnFixtureTest|
|firstPart|secondPart|together?|totalLength?|
|Hello|World|Hello, World|10|
|Houston|We Have a Problem|Houston, We Have a Problem|24|

Fixture class


fixture 클래스는 fit.ColumnFixture를 extend 해야 합니다. 그리고 테이블의 두번째 줄과 매치되는 public field들과 메소드들을 선언합니다.




Java Source Code

package info.fitnesse.fixturegallery;

import fit.ColumnFixture;

public class ColumnFixtureTest extends ColumnFixture {
	public String firstPart;
	public String secondPart;
	private int length;
	public String together(){
		length=firstPart.length()+secondPart.length();
		return firstPart+ ", "+secondPart;
	}
	public int totalLength(){
		return length;
	}
}

.NET Source Code

using System;
using System.Collections.Generic;
using System.Text;

namespace info.fitnesse.fixturegallery
{
    public class ColumnFixtureTest: fit.ColumnFixture
    {
        public String firstPart;
        public String secondPart;
        public String Together
        {
            get
            {
                return firstPart + ", " + secondPart;
            }
        }
        public int TotalLength()
        {
            return firstPart.Length+secondPart.Length;
        }
    }
}

Python Source Code

from fit.ColumnFixture import ColumnFixture

class ColumnFixtureTest(ColumnFixture):
    _typeDict = {
        "firstPart":  "String",
        "secondPart": "String"
    }

    def __init__(self):
        ColumnFixture.__init__(self)
        self.firstPart  = ""
        self.secondPart = ""

    # JAVA: public String together(){
    _typeDict["together"] = "String"
    def together(self):
        return "%s, %s" % (self.firstPart, self.secondPart)

    # JAVA: public int totalLength(){
    _typeDict["totalLength"] = "Integer"
    def totalLength(self):
        return len(self.firstPart) + len(self.secondPart)


Notes


자바버전에서는 클래스 필드들은 오직 input으로 사용되고 클래스 메소드들은 output으로 사용될 수 있습니다. JavaBean 프로퍼티들은 직접적으로 support 되지는 않습니다. (getter들이 output method들의 역할을 할 겁니다. 여러분은 getCreditLimit와 같은 전체 메소드 이름을 명시해야 합니다. .NET 버전에서는 필드들과 프로퍼티들이 input과 output들로 사용될 수 있습니다. 게다가 파라미터가 없는 메소드들도 output으로 사용될 수 있습니다. Java implementation은 대소문자 구분을 합니다. (case sensitive) .NET 버전은 프로퍼티 이름들에 대소문자 구분을 무시합니다.

table row들은 top-down 으로 실행됩니다. cell들도 왼쪽에서 오른쪽으로 실행되구요. 만약 row들이 실행되는 사이에 어떤 특별한 cleanup을 해야 한다면  reset() 메소드를 override하시면 됩니다.

.NET 버전은 ColumnFixture 로 domain object들을 감쌉니다. 이렇게 하면 fixture내의 도메인 object들의 프로퍼티들과 메소드들을 재선언 하지 않고 ColumnFixture 를 사용할 수 있도록 해 줍니다. Target objects로 가시면 좀 더 자세한 내용을 보실 수 있습니다.

output cell 을 empty로 놔두면 아무것도 테스트 하지 않고 현재의 값이 표시 됩니다.

Usage

 
ColumnFixture 는 calculation-based business rule들과 state machine들에 대해 테스트를 만들 떄 적합합니다. 같은 타입의 calculation이 다른 input 값들을 받아서 결과를 테스트하는 작업을 할 때 아주 유용합니다.

만약 테스트가 반복적이지 않다면 ColumnFixture 를 사용하는 것이 아주 좋은 방법이 아닐 수 있습니다. DoFixture (see DoFixture )를 한번 고려해 보세요. 만약 object들의 다이나믹한 리스트를 테스트하시려면 ArrayFixture (see ArrayFixture) 나 RowFixture 를 사용하세요. 이 Fixture들은 contents들도 verify 하거든요.


사람들은 가끔 이 ColumnFixture 를 잘 못 사용하기도 합니다. 특히 domain object나 데이터베이스에 record들을 insert 할 때 말이죠. 이를 위해서는 테이블의 마지막 칼럼에서 Create 를 call 함으로서 추가적인 메소드를 실행시킵니다. 이 메소드는 OK 같은 status code를 return 합니다. 이것은 creation에 대한 비지니스 룰을 체크하기를 원할 때 사용하면 좋습니다. 다른 테스트들의 stage를 준비하기를 원하신다면 SetUpFixture (see SetUpFixture )를 사용하면 좋습니다. 이 Fixture는 test page를 좀 더 가독성 있도록 해 줍니다. 또한 코드량도 줄일 수 있습니다.


반응형


반응형

지난번에도 Mockito 를 다룬적이 있는데요.

그 때는 다른 블로그에 있는 Mockito 관련 글을 번역해서 공부해 봤습니다.

예제들도 Android 를 중심으로 만들었구요.

 

오늘은 제가 참여하고 있는 Spring Framework에서 jUnit 테스트를 Mockito 를 사용해서 만든 경험을 정리해 보겠습니다.

 

일반적으로 jUnit 테스트 만드는 방법을 웹에서 검색하면 아주 간단한 예제들이 나옵니다.

하지만 실제 프로젝트에서 jUnit 테스트를 만들다 보면 이게 그렇게 간단하지 않거든요.

 

테스트하는 메소드 내에서 다른 메소드를 호출해서 return 값을 받아서 그 다음 일을 진행하기도 하고 또 호출한 메소드 내에서 또 다른 메소드의 호출이 일어나기도 하고요.

 

이럴 경우 Mockito 를 사용하는데 이번에 제가 실제 프로젝트에 참여하면서 경험하고 배운 내용을 정리합니다.

 

Spring Framework에는 Controller - Service - Transaction 이렇게 세개의 Layer로 나눠집니다.

 

Controller 부분은 Client Web 부분과 소통하고 Transaction은 SOA 나 DB 랑 소통합니다.

 

 

 

제가 참여하는 프로젝트의 흐름을 간단히 설명 드리면 Client 웹 브라우저의 form 문을 통해서 Controller에 어떤 데이터가 전달 됩니다. (이 때 세션값들도 받구요.)

그럼 Controller에서는 이 데이터를 기반으로 Bean 을 만들어 Service Layer로 던집니다. 그러면 Service Layer에서는 DTO를 만들어 Transaction으로 패스하고 Transaction에서는 Request를 Web Service 로 보냅니다.

웹 서비스에서는 다른 시스템이나 디비와 소통하면서 Response를 받아 Transaction으로 던져 주고요. Transaction은 이 Response를 가지고 DTO를 만들어서 Service로 던져 줍니다.

그러면 이 Service에서는 이를 다시 Bean으로 만들어 Controller로 패스하구요.

Controller는 이 Bean을 가지고 ModelAndView를 만들어서 Client의 웹 브라우저로 전달해서 그 다음 서비스를 사용자에게 전달합니다.

 

대부분의 중요한 비지니스 로직은 다른 외부 시스템에서 많이 진행 되서 이 자바 콤포넌트 내에서는 크게 비지니스 로직이 있지는 않습니다.

 

여기서 Controller에 있는 한 Method에 대해 jUnit 테스트를 만들게 되면 이 메소드가 Service 의 메소드를 호출하고 이 서비스에서는 다시 Transaction을 호출하고 여기서 다시 웹서비스를 call 해서 거기서 어떤 응답을 받게 되는 모든 과정이 진행됩니다.

 

그래서 단순하게 Controller에 있는 한 Method를 테스트 하려면 이 Service 에 있는 Method를 Call 하는 부분에서 그 return 값을 Mock 하면 됩니다.

 

이를 위해 저는 Mockito를 사용합니다.

 

아래는 지금 주료 사용하는 Mockito의 주요 기능을 정리합니다.

 

@RunWith(MockitoJUnitRunner.class)

처음 Mockito를 사용한다고 선언하는 부분입니다.

프로젝트에서 사용하는 소스코드를 사용할 수 없어서 API 에 있는 예제를 가지고 설명하겠습니다.

 

@RunWith(MockitoJUnitRunner.class)
public class ExampleTest {

    @Mock
    private List list;

    @Test
    public void shouldDoSomething() {
        list.add(100);
    }
}

이 예제는 여기 에 있는 API 문서에 있는 예제입니다.

 

우선 클래스 이름 선언하는 부분 위에 @RunWith(MockitoJUnitRunner.class) 를 선언함으로서 이 클래스에서 Mockito를 사용할 것이라는 것을 알립니다.

 

@Mock

그 다음에 private List list: 위에 @Mock 이라고 돼 있는데요.

이 부분을 Mock 할 거라는 것을 알리는 겁니다.

 

 

@InjectMocks

이 Annotation을 설명하기 위해 다른 예제를 보여드리겠습니다.

이 예제는 여기로 가시면 보실 수 있습니다.

 

public class ArticleManagerTest extends SampleBaseTestCase {

    @Mock private ArticleCalculator calculator;
    @Mock(name = "database") private ArticleDatabase dbMock; // note the mock name attribute
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @InjectMocks private ArticleManager manager;

    @Test public void shouldDoSomething() {
        manager.initiateArticle();
        verify(database).addListener(any(ArticleListener.class));
    }
}

public class SampleBaseTestCase {

    @Before public void initMocks() {
        MockitoAnnotations.initMocks(this);
    }
}

 

이렇게 사용하는데요. Mock 한 데이터를 이 @injectMocks 가 선언된 변수에 값을 inject하겠다는 내용입니다.주로 테스트하는 그 메소드에 이 inject 구문을 사용합니다. Mock 한 데이터를 넣어야 하는 곳이 그 메소드일 테니까요.

 

 

다음은 when().then() 구문을 설명할 텐데요.

when(mockedList.get(0)).thenReturn("first");

 

이 코드는 mockedList.get(0) 이라는 부분이 오면 그 return 값으로 first라는 스트링을 넣으라고 하는 명령입니다.

이게 바로 Controller에서 Service Layer에 있는 메소드를 호출 했을 때 이 Service 에 있는 메소드를 실행하지 않고 그 return 값을 mock 할 때 사용하는 구문입니다.

 

제가 참여하는 프로젝트에서는 이런식으로 사용됩니다.

when(service.method(isA(bean.class)).thenReturn(Bean)

 

클래스 이름이나 메소드 이름 그리고 input, return 파라미터 값들은 임의로 정한겁니다.

이 구문을 해석하자면 service 클래스에 있는 method라는 메소드가 호출 되면, 이때 method의 input 값은 bean.class 일 경우 입니다. 하여간 이 method가 호출되면 Bean을 return 하라는 명령입니다.

이전에 Bean을 별도로 생성해서 데이터를 세팅해 놔야 합니다.

 

이상이 제가 참여하는 프로젝트에서 jUnit 테스트를 만들 때 주로 사용하는 Mockito 기능들입니다.

저 위에 예제에서 나왔던 spy()라는 것도 몇군데 사용했는데요. 많이 사용하지는 않았습니다.

 

이 외에 Mockito 명령문은 아니지만 주로 많이 사용했던게 ReflectionTestUtils.setField 인데요.

 

Controller나 Service Layer 등등에서 다른 Layer의 메소드가 아니라 같은 Layer의 utility 클래스나 validator 클래스의 메소드를 호출하는 경우가 많이 있습니다.

 

이 때 이것을 사용했는데요. 다른 클래스의 메소드를 Mock instance로 처리하는 명령어 입니다.

이 기능은 Mockito의 기능이 아니라 Spring Framework의 API 인것으로 알고 있습니다.

 

 

 

반응형

Fitnesse 사용법 간단 정리

2013. 8. 7. 12:42 | Posted by 솔웅


반응형

요즘 제가 참여하는 프로젝트에 적용하려고 Fitnesse 를 Research 하고 있습니다.


나중을 위해서 간단하게 정리해 두겠습니다.


저는 FitLibrary 에 대해 알아보려고 검색하다가 관련된 파일을 다운 받았습니다.

정확히 다운 받은 곳을 못 찾겠네요.


필요하신 분은 구글링해서 다운 받으시기 바랍니다.

제가 다운 받은 파일 이름은 FitLibrary-2.0.zip 입니다.


Fitnesse 실행은 아래와 같이 합니다.


java -jar fitnesse-standalone.jar -o -p 8980 -e 0

 


처음 압축을 풀면 FitLibrary-2.0\fitnesse 폴더 내에 fitnesse-standalone 를 복사해 넣고 runFitNesseDirectly.bat 라는 배치 파일을 아래와 같이 수정하신 후 그 배치 파일을 실행 시키시면 됩니다.


java -jar fitnesse-standalone.jar -o -p 8980 -e 0
pause


이렇게 하고 나면 아래와 같은 콘솔이 뜹니다.


 

이제 Fitnesse 가 실행 된 겁니다.

 

브라우저를 열고 localhost:8980 에 접속해 보세요.

 

 

 

이 화면은 제가 좀 편집을 한 화면 입니다.

 

하여간 여러분도 성공하셨다면 비슷한 화면을 보실 겁니다.

 

여기서 테스트 테이블을 만들고 Fixture 작성해보고 또 test 를 실행해 보고 하는 것은 관련 예제들이 구글에 많이 있으니 그 예제들을 참고하시면 됩니다.

 

제가 작업하는 환경은 Spring Frame work 인데요.

이 프로젝트의 클래스들을 테스트 하기 위한 세팅방법을 Research 했었습니다.

 

그 클래스를 테스트 하려면 우선 해당 클래스들이 있는 jar 파일의 경로를 Fitnesse의 테이블 만드는 곳에서 설정을 해야 합니다.

 

!path C:\pcs\Fitnesse\java; ....

이런식으로요.

 

저는 프로젝트 build 한 후 target 폴더에 있는 jar 파일들을 임의의 폴더로 복사하고 그곳에 있는 jar 파일들을 path 에 적어 넣었습니다.

 

그 다음에는 Fixture 클래스를 생성할 프로젝트를 만듭니다.

저는 이클립스에 만들었습니다.

 

여기서 위의복사해 넣은 jar들을 프로젝트에 추가 시켜서 관련 테스트 Fixture를 만듭니다.

 

그리고 FItness 웹에 들어와서 관련된 테스트 테이블을 만들면 됩니다.

 

 

 

 

 

제가 샘플로 만들어 본 테스트 입니다.

 

이걸 save 한 다음 test 를 돌려보면 아래와 같은 결과를 얻을 수 있습니다.

 

 

 

 

오늘은 제가 요즘 research 하고 있는 것들을 기억해 두려고 간단하게 정리해 봤습니다.

 

다음에 기회가 되면 좀 더 디테일하고 실전에서 활용되는 팁을 정리하도록 하겠습니다.

반응형

Mockito로 테스트 하기

2013. 6. 17. 08:06 | Posted by 솔웅


반응형

오늘은 Lars Vogel 라는 친구가 작성한 Mockito 튜토리얼을 공부했습니다. 2012년 6월에 작성해서 2013는 2월에 Revision 됐으니까 아주 최근 글이네요. Mockito 에 대한 기본 설명과 예제가 있고 예제는 안드로이드 프로젝트에서 사용할 때의 예제를 보여 줍니다.

글 제목을 클릭하시면 원본이 있는 페이지로 가실 수 있습니다. 고맙게 자신이 어렵게 얻은 지식을 이렇게 공유해 주고 있는 친구에게 도움을 주는게 기본 예의 아닐까 합니다. 해당 페이지에는 Donation 할 수 있는 링크도 있고 광고도 있으니까 이 중 할 수 있는 방법으로 도움을 주실 수 있을 거예요. :)

 

Testing with Mockito - Tutorial

Lars Vogel

 

 


Version 1.1

02.05.2013


Testing with Mockito

이 튜토리얼은 이클립스에서 모키토 프레임워크로 테스트 하는 방법을 설명하고 있습니다.


 


1. Prerequisites

아래 튜토리얼은 JUnit 프레임워크로 단위테스트하는 것을 기반으로 작성했습니다.

JUnit 를 잘 모르신다면 JUnit Tutorial 를 참조하세요.

 


2. Testing with mock objects


Unit testing은 클래스나 메소드별로 별도로 테스팅하는 것을 말합니다.


자바 클래스들은 대개 다른 클래스들에 의존 합니다. mock object는 특정 메소드 호출에 어떤 output을 정의한 인터페이스나 클래스에 대한 dummy implementation을 말합니다. Mock object들은 dependency 없이 테스트 되어야 하는 클래스에 대한 단위테스트를 만들 때 유용하게 사용됩니다.


코드를 작성해서 이 mock object들을 생성하거나 이 클래스들을 simulate 하기 위해 mock framework을 사용할 수 있습니다. Mock frameworks는 runtime에 mock object들을 생성할 수 있도록 하고 그 behavior를 정의할 수 있도록 해 줍니다.

mock object에 대한 고전적인 예제는 data provider를 들 수 있습니다.  production에서는 실제 데이터베이스가 사용되지만 테스팅에서는 mock object를 사용해서 데이터베이스를 simulate 해야 합니다. 실제 데이터베이스를 사용할 때와 똑같은 상황을 만들어 놓고 테스트를 해야 되는 거죠.

이 mock object들은 테스트 될 클래스에 제공될 수 있습니다. 그래서 테스트 해야할 클래스가 외부 데이터에 대한 의존(dependency) 없이 동작하고 그 결과를 테스트 할 수 있습니다.

Mock frameworks는 또한 mock object 와의 상호작용(interaction)을 가능하게 해 그에 따른 테스트를 진행할 수 있도록 합니다. 예를 들어 mock object에 의해 call 된 메소드를 테스트를 하는 경우가 이 경우가 되겠죠.


 


3. Mockito


3.1. The Mockito testframework

Mockito 프레임워크에 대해서는 Mockito homepage 에 가시면 자세한 내용을 보실 수 있습니다.

Mockito 는 여러분에게 항상 mock objects를 생성할 수 있도록 기능을 제공합니다. 이 mock objects들은 method를 호출할 때 Pass 되도록 할 수 있어 그 메소드를 테스트 할 수 있도록 도와 줍니다.

 

3.2. Using Mockito

Mockitomock() 메소드를 call 해서 생성하거나 @Mock annotation에 근거해서 생성할 수 있습니다. annotation이 사용됐다면 MockitoAnnotations.initMocks(this) method call을 사용해서 초기화 해야 합니다.

아래의 예제를 보세요.

 

public static Intent createQuery(Context context, String query, String value) {
    Intent i = new Intent(context, MyListActivity.class);
    i.putExtra("QUERY", query);
    i.putExtra("VALUE", value);
    return i;
  } 

 

이 메소드는 Context 에 대해 mock object를 만들어서 테스트 할 수 있습니다.

 

package com.vogella.android.mockito.intent.test;

import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.test.AndroidTestCase;

import com.vogella.android.mockito.intent.MainActivity;

public class MainActivtityTest extends AndroidTestCase {
  @Mock
  Context context;

  @Override
  protected void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
  }

  public void testQuery() throws Exception {
    Intent intent = MainActivity.createQuery(context, "query", "value");
    assertNotNull(intent);
    Bundle extras = intent.getExtras();
    assertNotNull(extras);
    assertEquals("query", extras.getString("QUERY"));
    assertEquals("value", extras.getString("VALUE"));
  }
} 

Note

이 예제 코드는 단지 간단한 사용법을 보여 드리기 위한 겁니다. 이 예제는 안드로이드 프로그래밍을 예로 들었습니다. Android 에서 Mockito를 direct 하게 사용할 수 있습니다.

Tip

Static imports allows you to call static members, i.e. methods and fields of a class directly without specifying the class. If you declare Mockito.* as static member you can access methods like mock() directly.

 

 

Mockito 에는 아주 훌륭한 API 가 있습니다. verify() method 를 사용해서 해당 메소드가 호출 됐는지 여부를 확인 할 수 있습니다.

when(....)thenReturn(....) 를 사용하면 특정 상황에서의 return 값을 정해 줄 수 있습니다.

doReturn(object).when(kdskfsk).methodCall 도 비슷한 일을 합니다.

특정 상황을 체크하기 위해 mock object에 verify() method 를 사용해도 됩니다.

@Spy 나 spy() method 는 real object를 wrap 하기 위해 사용할 수 있습니다. Every call, unless specified otherwise is delegated to the object.

 

// Lets mock a LinkedList
List list = new LinkedList();
List spy = spy(list);

//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

// this would not work
// real method is called so spy.get(0)
// throws IndexOutOfBoundsException (list is still empty)
when(spy.get(0)).thenReturn("foo");

 

verifyNoMoreInteractions()는 더이상의 메소드 호출이 없음을 체크할 수 있도록 합니다.

 


4. Mockito on Android

release 1.9.5 Mockito 부터 Android 에서 direct로 사용할 수 있도록 됐습니다. 안드로이드 테스트 프로젝트에서 Mockito를 사용하려면 안드로이드 테스트 프로젝트의 libs 폴더에 아래 세개의 라이브러리를 추가 하시면 됩니다.

https://mockito.googlecode.com/files/mockito-all-1.9.5.jar
http://dexmaker.googlecode.com/files/dexmaker-1.0.jar
http://dexmaker.googlecode.com/files/dexmaker-mockito-1.0.jar 


 

5. Thank you

이 글이 괜찮으시다면 도움을 주세요.

여기 로 가시면 도움을 주실 수 있는 방법이 있습니다.


6. Questions and Discussion

질문을 올리시기 전에vogella FAQ 를 먼저 보시면 도움이 되실 겁니다. 이 글을 보시고 질문이 있으시거나 에러를 발견하셨다면 www.vogella.com Google Group를 이용해 주세요. how to create good questions 도 만들었습니다. 이 글을 보시면 여로분께 도움이 되실 겁니다.

 

7. Links and Literature  

7.1. EasyMock

EasyMock Homepage



반응형

jUnit 으로 Private Method 테스트 만들기 2

2013. 6. 10. 10:04 | Posted by 솔웅


반응형

지난번 글에 jUnit으로 Private Method 만들기를 올렸는데요.

 

input 파라미터가 class가 아니라 type 일 때 좀 헛갈려 하는 친구가 있더라구요.

 

기본 데이터 타입을 다룰 때는 class 대신 TYPE을 사용하시면 됩니다.

 

Integer 를 예로 들어서 실습을 해 볼께요.

 

    private int jUnitPrivate2(int a, int b) {
        int result = 0;
        result = a + b;
        return result;
    }

 

테스트 할 원래 코드는 위와 같습니다.

 

지난번 글에서 String 대신 Integer를 파라미터로 사용하시면 됩니다.

이에 대한 테스트 코드는 아래와 같습니다.

 

   @Test
    public void testJunitPrivate2() {
       
        Method m;   
        Class[] methodParameters = new Class[]{Integer.TYPE, Integer.TYPE};

        try
        {
            m = jPrivate.getClass().getDeclaredMethod("jUnitPrivate2",methodParameters);
            m.setAccessible(true);
           
            int result =0;
            int a = 111;
            int b = 222;
               
            try
            {
                result = (Integer) m.invoke(jPrivate,a,b);
            }
            catch (Exception e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
                       
            assertEquals(333,result);
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

 

 

String.class 대신 Integer.TYPE 이 들어갔습니다.

다른 건 없습니다.

 

 

 

지난번 테스트 소스에 추가를 했습니다.

보시다시피 지난번 jUnit test 하고 이번에 Integer 를 사용한 private class 를 테스트한 jUnit test 하고 모두 통과 됐습니다.

 

privatemethod.java

 

jUnitPrivateTest.java

반응형
이전 1 ··· 5 6 7 8 9 다음