2016년 1월 3일 일요일

Page Object

요즘 업무 시간에 UI테스트를 자동화하고 있다. Selenium을 이용해서 하고 있는데, 관련 서적이나 블로그를 보면 항상 Page Object를 사용하도록 추천하고 있다. 관련된 마틴 파울러의 블로그를 읽으면서 내용을 정리했다.


웹페이지에 대한 테스트를 작성할 때, 웹페이지 내부의 HTML 요소를 직접 제어하지 말자. UI가 변경되면 테스트코드도 변경되어야 하므로, HTML 페이지의 구성요소와 기능을 래핑한 Page Object를 사용해서 테스트코드를 만들자. [그림참고]

Page Object의 기본 규칙은 사람이 해당 페이지에 대해서 볼 수 있는 것은 그대로 보여야 하고, 할 수 있는 것도 그대로 할 수 있어야 한다는 것이다. 인터페이스를 제공하고, 페이지 내부의 구성요소를 제어하는 로직은 숨겨야 한다. 텍스트 필드에 접근하고자 할 때에는 문자열을 받거나 리턴하는 메서드를 통해야 한다. 체크박스는 boolean을 사용하고, 버튼은 해당 버튼의 기능을 표현하는 메서드를 사용해야 한다. Page Object는 UI 내부 데이터를 제어하는 로직을 캡슐화해야한다. 인터페이스는 바뀌지 않고 실제 구현 클래스만 바뀌는 경우가 그러할 것이다.

"page"라는 용어를 사용하지만, 모든 웹페이지의 Page Object를 만들 필요는 없다. 중요한 구성요소에 대해서만 만들어서, 여러 앨범을 표시하는 웹페이지가 있다면 앨범 Page Object의 목록을 구성해서 활용하면 될 일이다. 헤더나 푸터 Page Object도 비슷하게 웹페이지를 구조화할 수 있을 것이다.

비슷한 방식으로, 다른 웹페이지로 이동하는 경우에는 초기 Page Object가 이동하는 Page Object를 리턴하게 만들면 될 것이다.

Page Object가 assertion을 내부에 가지고 있어야 하는지 아닌지에 대한 여러가지 의견이 있을 수 있다. 내부에 가지고 있게 되면, 중복되는 assertion을 제거하고, 좀 더 좋은 에러 메시지를 외부에 제공할 수 있을 것이다. 그렇게 해서 TellDontAsk 스타일의 API를 구성할 수 있다. 내부에 assertion이 없다면, Page Object를 좀 더 간결하게 유지할 수 있어서 내부 데이터에 대한 접근과 assertion 로직을 분리하기가 쉬울 것이다.

나는(마틴 파울러) assertion이 없는 Page Object를 더 선호한다. 공통의 assertion library를 통해서 중복되는 assertion을 피할 수 있을 것이고, 간단하게 웹페이지에 대한 기본적인 검증을 쉽게 할 수 있을 것이다.

Page Object는 보통 테스트에 사용되지만, 스스로 assertion을 해서는 안될 것이다. 단순히 내부 데이터와 구성요소에 대한 접근을 제공하고, assertion에 대해서는 테스트코드에서 수행되도록 유도해야 할 것이다.

HTML에 대해서만 이 패턴을 설명했지만, 어떤 다른 UI에 대해서도 동일하게 적용할 수 있을 것이다. Java의 swing UI를 사용할 때 잘 사용되는 것을 실제로 봤었고, 다른 어떤 UI에서도 잘 될것이라 의심치 않는다.

동시성 문제로 Page Object가 캡슐화할 수 있는 영역이다. 사용자에게는 async로 보이지 않는 async 동작을 그렇지 않게 숨길 수가 있다. (무슨 말이지?) 스레드 이슈도 캡슐화할 수 있다. UI와 worker간의 동작을 신경써야 하는 UI 프레임웍을 쓴다면 아마 해결 가능할 것이다. (이거도 무슨 소리지?)

Page Object는 대부분 테스트 영역에서 사용되지만, 일반 애플리케이션에서 스크립트 형식의 인터페이스를 제공하는 것으로도 사용될 수 있다. 보통은 UI 내부에 스크립트 인터페이스를 구축하는 것이 일반적이고, 덜 복잡하고 빠르다. 그런데 UI에 기능이 너무 많은 경우에는 Page Object를 쓰는 것이 좋지 않을 것이다. (이런 경우라면 로직을 분리하는 방안을 고려해봐야 한다. 그게 스크립트를 만드는 데도 도움이 되고, UI 자체도 장기적인 관점에서 도움이 될 것이다.)


댓글 없음:

댓글 쓰기