IT박스

테스트 구성을위한 PHPUnit 모범 사례

itboxs 2020. 11. 15. 11:04
반응형

테스트 구성을위한 PHPUnit 모범 사례


저는 현재 프로젝트에 대한 phpunit 테스트를 처음부터 시작할 것입니다. 그래서 저는 Zend와 같은 일부 프로젝트를 조사하여 그들이 어떻게 일을하고 있는지 그리고 어떻게 테스트를 구성하는지 확인했습니다.

대부분의 것들은 꽤 분명합니다. 제가 몇 가지 문제를 가지고있는 유일한 것은 테스트 스위트를 올바르게 구성하는 방법입니다. Zend에는 다른 테스트 스위트를로드하는 AllTests.php가 있습니다.
클래스를 살펴보면 PHPUnit_Framework_TestSuite스위트 객체를 만든 다음 다른 스위트를 추가하는 데 사용하는 클래스를 살펴 보지만 3.4 이후 PHPUnit 버전에서 테스트를 구성하기위한 PHPUnit 문서를 보면 XML 또는 FileHierarchy에 대한 설명 만 있습니다. 테스트를 구성하기 위해 클래스를 사용하는 것은 제거되었습니다.
이 방법이 더 이상 사용되지 않으며 Zend와 같은 프로젝트에서 여전히 사용하고 있다는 사실을 발견하지 못했습니다.

그러나 더 이상 사용되지 않는 경우 xml 구성을 사용하여 동일한 구조로 테스트를 구성하려면 어떻게해야합니까? 모든 테스트를 실행하는 것은 문제가되지 않지만 몇 가지 테스트 만 실행하려는 경우 어떻게 xml에서 테스트를 구성 할 수 있습니까? 실행할 테스트 / 테스트 스위트를 몇 개만 지정하는 여러 xml을 만들 수 있습니까?

따라서 응용 프로그램의 module1 및 module2 만 테스트하려면 각각에 대한 추가 xml이 있고 해당 모듈 (모듈에서 사용하는 클래스)에 대해서만 테스트 스위트를 정의합니다. 그리고 모든 테스트에 대한 테스트 스위트를 정의하는 것도 있습니까?

아니면 @group특정 테스트에 대한 주석 을 사용하여 module1 또는 module2에 대한 것으로 표시하는 것이 더 낫습니까?

몇 가지 모범 사례를 알려 주셔서 미리 감사드립니다.


먼저 매뉴얼에 연결 한 다음 현장에서보고들은 내용을 살펴 보겠습니다.

phpunit 테스트 스위트 구성

파일 시스템의 모듈 / 테스트 폴더 구성

필자가 권장하는 방법은 파일 시스템을 xml 구성과 결합하는 것입니다.

tests/
 \ unit/
 | - module1
 | - module2
 - integration/
 - functional/

A를 phpunit.xml간단한과 :

<testsuites>
  <testsuite name="My whole project">
    <directory>tests</directory>
  </testsuite>
</testsuites>

원하는 경우 테스트 스위트를 분할 할 수 있지만 프로젝트에서 프로젝트로 선택하는 것입니다.

Running phpunit은 모든 테스트를 실행하고 running phpunit tests/unit/module1은 module1의 모든 테스트를 실행합니다.

"unit"폴더의 구성

여기서 가장 일반적인 접근 방식은 폴더 구조 source/에서 디렉토리 구조 를 미러링하는 것 tests/unit/입니다.

어쨌든 ProductionClass 당 하나의 TestClass가 있으므로 내 책에서 좋은 접근 방식입니다.

파일 구성

  • 파일 당 하나의 클래스.

하나의 파일에 둘 이상의 테스트 클래스가 있으면 어쨌든 작동하지 않으므로 그 함정을 피하십시오.

  • 테스트 네임 스페이스가 없습니다.

추가 use 문이 필요하므로 테스트를 더 장황하게 작성하므로 testClass가 프로덕션 클래스와 동일한 네임 스페이스에 있어야하지만 PHPUnit이 강제로 수행해야하는 작업은 아닙니다. 나는 결점없이 더 쉽다는 것을 방금 발견했습니다.

몇 가지 테스트 만 실행

예를 들어 phpunit --filter Factory모든 FactoryTests를 phpunit tests/unit/logger/실행하고 관련된 모든 로깅 실행합니다.

@group이슈 번호, 이야기 등에 태그를 사용할 수 있지만 "모듈"에는 폴더 레이아웃을 사용합니다.

여러 XML 파일

다음과 같은 경우 여러 xml 파일을 만드는 것이 유용 할 수 있습니다.

  • 코드 커버리지가없는 것
  • 하나는 단위 테스트 전용입니다 (하지만 기능, 통합 또는 장기 실행 테스트에는 해당되지 않음).
  • 기타 일반적인 "필터"사례
  • 예를 들어 PHPBB3는 their phpunit.xmls

테스트를위한 코드 커버리지

테스트를 통해 새 프로젝트를 시작하는 것과 관련이 있습니다.

  • 내 제안은 내 블로그에 설명 된@covers 태그 를 사용하는 입니다 (단위 테스트의 경우에만 항상 공개 기능이 아닌 모든 기능을 포함하고 항상 표지 태그를 사용).
  • 통합 테스트에 대한 커버리지를 생성하지 마십시오. 그것은 당신에게 잘못된 보안 감각을 제공합니다.
  • 항상 화이트리스트를 사용하여 모든 프로덕션 코드를 포함하여 숫자가 거짓말을하지 않도록하십시오!

테스트 자동 로딩 및 부트 스트랩

테스트를 위해 어떤 종류의 자동 로딩도 필요하지 않습니다. PHPUnit이 처리합니다.

사용 <phpunit bootstrap="file">테스트 부트 스트랩을 지정하는 속성. tests/bootstrap.php그것을두기에 좋은 곳입니다. 여기에서 애플리케이션 자동 로더 등을 설정할 수 있습니다 (또는 해당 문제에 대해 애플리케이션 부트 스트랩을 호출).

요약

  • Use the xml configuration for pretty much everything
  • Seperate unit and integration tests
  • Your unit test folders should mirror your applications folder structure
  • To only execute specif tests use phpunit --filter or phpunit tests/unit/module1
  • Use the strict mode from the get go and never turn it off.

Sample projects to look at


Basic Directory Structure:

I have been experimenting with keeping the test code right next to the code being tested, literally in the same directory with a slightly different file name from the file with the code it is testing. So far I am liking this approach. The idea is you don't have to spend time and energy keeping the directory structure in sync between your code and your test code. So if you change the name of the directory the code is in, you don't then also need to go and find and change the directory name for the test code. This also causes you to spend less time looking for the test code that goes with some code as it is right there next to it. This even makes it less of a hassle to create the file with the test code to begin with because you don't have to first find the directory with the tests, possibly create a new directory to match the one you are creating tests for, and then create the test file. You just create the test file right there.

One huge advantage of this is it means the other employees (not you because you would never do this) will be less likely to avoid writing test code to begin with because it is just too much work. Even as they add methods to existing classes they will be less likely to not feel like adding tests to the existing test code, because of the low friction of finding the test code.

One disadvantage is this makes it harder to release your production code without the tests accompanying it. Although if you use strict naming conventions it still might be possible. For example, I have been using ClassName.php, ClassNameUnitTest.php, and ClassNameIntegrationTest.php. When I want to run all the unit tests, there is a suite that looks for files ending in UnitTest.php. The integration test suite works similarly. If I wanted to, I could use a similar technique to prevent the tests from getting released to production.

Another disadvantage of this approach is when you are just looking for actual code, not test code, it takes a little more effort to differentiate between the two. But I feel this is actually a good thing as it forces us to feel the pain of the reality that test code is code too, it adds its' own maintenance costs, and is just as vitally a part of the code as anything else, not just something off to the side somewhere.

One test class per class:

This is far from experimental for most programmers, but it is for me. I am experimenting with only having one test class per class being tested. In the past I had an entire directory for each class being tested and then I had several classes inside that directory. Each test class setup the class being tested in a certain way, and then had a bunch of methods each one with a different assertion made. But then I started noticing certain conditions I would get these objects into had stuff in common with other conditions it got into from other test classes. The duplication become too much to handle, so I started creating abstractions to remove it. The test code became very difficult to understand and maintain. I realized this, but I couldn't see an alternative that made sense to me. Just having one test class per class seemed like it would not be able to test nearly enough situations without becoming overwhelming to have all that test code inside one test class. Now I have a different perspective on it. Even if I was right, this is a huge dampener on other programmers, and myself, wanting to write and maintain the tests. Now I am experimenting with forcing myself to have one test class per class being tested. If I run into too many things to test in that one test class, I am experimenting with seeing this as an indication that the class being tested is doing too much, and should be broken up into multiple classes. For removing duplication I am trying to stick to simpler abstractions as much as possible that allows everything to exist in one readable test class.

UPDATE I am still using and liking this approach, but I have found a very good technique for reducing the amount of test code and the amount of duplication. It is important to write reusable assertion methods inside the test class itself that gets heavily used by the test methods in that class. It helps me to come up with the right types of assertion methods if I think of them as internal DSLs (something Uncle Bob promotes, well actually he promotes actually making internal DSLs). Sometimes you can take this DSL concept even further (actually make a DSL) by accepting a string parameter that has a simple value that refers to what kind of test you are trying to perform. For example, one time I made a reusable asssertion method that accepted a $left, $comparesAs, and a $right parameter. This made the tests very short and readable as the code read something like $this->assertCmp('a', '<', 'b').

Honestly, I can't emphasize that point enough, it is the entire foundation of making writing tests something that is sustainable (that you and the other programmers want to keep doing). It makes it possible for the value that tests add to more than what they take away. The point is not that you need to use that exact technique, the point is you need to use some kind of reusable abstractions that allow you to write short and readable tests. It might seem like I'm getting off topic from the question, but I'm really not. If you don't do this, you will eventually fall into the trap of needing to create multiple test classes per class being tested, and things really break down from there.

참고URL : https://stackoverflow.com/questions/8313283/phpunit-best-practices-to-organize-tests

반응형