Program Tip

단위 테스트 채택

programtip 2020. 11. 3. 18:54
반응형

단위 테스트 채택


현재 프로젝트에 단위 테스트를 도입하려고했지만 작동하지 않는 것 같습니다. 추가 코드는 내부 프레임 워크가 변경 될 때 문제가되는 단위 테스트를 수정해야하므로 유지 관리 문제가 된 것 같습니다.

자식 클래스의 추상 메서드 구현을 호출하는 템플릿 역할을하는 컨트롤러의 단위 테스트를위한 추상 기본 클래스가 있습니다. 즉 프레임 워크는 Initialize를 호출하여 컨트롤러 클래스가 모두 고유 한 Initialize 메서드를 갖습니다.

나는 단위 테스트의 옹호자 였지만 현재 프로젝트에서 작동하지 않는 것 같습니다.

누구든지 문제를 식별하고 단위 테스트가 우리에게 불리하지 않고 어떻게 작동하도록 할 수 있습니까?


팁 :

절차 적 코드 작성 방지

테스트가 전역 상태에 크게 의존하거나 추악한 메서드의 본문에 깊숙이 놓여있는 절차 적 스타일의 코드에 대해 작성된 경우 유지 관리해야 할 곰이 될 수 있습니다. OO 언어로 코드를 작성하는 경우 OO 구문을 효과적으로 사용하여이를 줄이십시오.

  • 가능하면 전역 상태를 피하십시오.
  • 정적은 코드베이스를 통해 파문을 일으키고 결국에는 안되는 것이 정적이되는 경향이 있으므로 피하십시오. 또한 테스트 컨텍스트를 부풀립니다 (아래 참조).
  • 과도한 if 및 플래그 를 방지하기 위해 다형성을 효과적으로 활용

변경 사항을 찾아 캡슐화하고 동일하게 유지되는 것과 분리하십시오.

코드에는 다른 부분보다 훨씬 자주 변경되는 초크 포인트가 있습니다. 코드베이스에서이 작업을 수행하면 테스트가 더 건강해질 것입니다.

  • 좋은 캡슐화는 좋고 느슨하게 결합 된 디자인으로 이어집니다.
  • 리팩터링 및 모듈화.
  • 테스트를 작고 집중적으로 유지하십시오.

테스트를 둘러싼 컨텍스트가 클수록 유지 관리가 더 어려워집니다.

테스트와 테스트가 실행되는 주변 컨텍스트를 축소하기 위해 가능한 모든 작업을 수행하십시오.

  • 구성된 메서드 리팩토링을 사용하여 더 작은 코드 청크를 테스트합니다.
  • TestNG 또는 JUnit4와 같은 최신 테스트 프레임 워크를 사용하고 있습니까? 테스트 수명주기에 대한보다 세분화 된 후크를 제공하여 테스트에서 중복을 제거 할 수 있습니다.
  • 테스트 컨텍스트의 크기를 줄이기 위해 테스트 이중 (모의, 가짜, 스텁)을 사용하여 조사하십시오.
  • 테스트 데이터 빌더 패턴을 조사하십시오 .

테스트에서 중복을 제거하되 초점을 유지해야합니다.

모든 중복을 제거 할 수는 없지만 통증을 유발하는 부분을 제거하려고합니다. 누군가가 들어올 수없고 테스트가 한눈에 무엇을하는지 말할 수 없을 정도로 중복을 너무 많이 제거하지 마십시오. ( 동일한 개념에 대한 다른 설명은 Paul Wheaton의 "Evil Unit Tests" 기사를 참조하십시오.)

  • 테스트가 무엇을하는지 파악할 수 없다면 아무도 테스트를 고치고 싶어하지 않을 것입니다.
  • Arrange, Act, Assert 패턴을 따르십시오.
  • 테스트 당 하나의 어설 션 만 사용하십시오.

확인하려는 항목에 대해 올바른 수준에서 테스트하십시오.

기록 및 재생 Selenium 테스트와 관련된 복잡성과 단일 방법 테스트와 비교하여 변경할 수있는 사항에 대해 생각해보십시오.

  • 서로 종속성을 분리하십시오.
  • 의존성 주입 / 제어 반전을 사용합니다.
  • 테스트를 위해 개체를 초기화하려면 테스트 double을 사용하고 단일 코드 단위를 격리하여 테스트해야합니다.
  • 관련 테스트를 작성하고 있는지 확인
    • 의도적으로 버그를 도입하여 "Spring the Trap"을 수행하고 테스트에 의해 잡히도록합니다.
  • 참조 : 통합 테스트는 사기입니다.

상태 기반 테스트와 상호 작용 기반 테스트를 사용해야하는 경우 파악

진정한 단위 테스트에는 진정한 격리가 필요합니다. 단위 테스트는 데이터베이스 나 오픈 소켓에 도달하지 않습니다. 이러한 상호 작용을 조롱하지 마십시오. 이 메소드 호출의 적절한 결과가 "42"인지 아닌지 확인하십시오.

테스트 구동 코드 시연

주어진 팀이 모든 코드를 테스트 운전할 것인지, 아니면 모든 코드 라인에 대해 "먼저 테스트"를 작성할 것인지는 논쟁의 여지가 있습니다. 하지만 적어도 몇 가지 테스트를 먼저 작성해야합니까? 물론. 의심 할 여지없이 테스트 우선이 문제에 접근하는 가장 좋은 방법 인 시나리오가 있습니다.

자원:


충분히 작은 코드 단위를 테스트하고 있습니까? 핵심 코드의 모든 것을 근본적으로 변경하지 않는 한 너무 많은 변경 사항을 볼 수 없습니다.

일단 안정되면 단위 테스트를 더 높이 평가할 수 있지만 지금도 테스트에서 프레임 워크 변경 사항이 전파되는 정도를 강조하고 있습니다.

그만한 가치가 있으며 가능한 한 최선을 다하십시오.


더 많은 정보가 없이는 왜 이러한 문제를 겪고 있는지 제대로 파악하기가 어렵습니다. 때로는 인터페이스 변경 등이 많은 것을 망가 뜨리는 것이 불가피한 경우도 있고, 디자인 문제로 귀결되는 경우도 있습니다.

보고있는 실패를 분류하고 분류하는 것이 좋습니다. 어떤 종류의 문제가 있습니까? 예를 들어 API 변경으로 인한 테스트 유지 관리 (리팩토링 후 컴파일하는 것과 같이!)입니까, 아니면 API 변경 동작으로 인한 것입니까? 패턴이 보이면 프로덕션 코드의 디자인을 변경하거나 테스트가 변경되지 않도록 더 잘 격리 할 수 ​​있습니다.

몇 가지 사항을 변경하면 여러 위치에서 테스트 스위트에 엄청난 피해를 입힐 수있는 몇 가지 작업이 있습니다 (대부분은 일반적인 단위 테스트 팁입니다).

  • 작은 코드 단위를 개발하고 작은 코드 단위를 테스트합니다. 코드 단위에 '이음새'가 포함되도록 의미있는 인터페이스 또는 기본 클래스를 추출합니다. 가져와야하는 종속성이 많을수록 (또는 'new'를 사용하여 클래스 내부에서 인스턴스화) 코드 변경에 더 많이 노출됩니다. 각 코드 단위에 소수의 종속성 (때로는 두 개 또는 전혀 없음)이 있으면 변경으로부터 격리하는 것이 좋습니다.

  • 테스트에 필요한 것만 주장하십시오. 중간, 부수적 또는 관련없는 상태에 대해 주장하지 마십시오. 계약별로 설계하고 계약별로 테스트합니다 (예 : 스택 팝 메서드를 테스트하는 경우 푸시 후 count 속성을 테스트하지 마십시오. 별도의 테스트에 있어야 함).

    I see this problem quite a bit, especially if each test is a variant. If any of that incidental state changes, it breaks everything that asserts on it (whether the asserts are needed or not).

  • Just as with normal code, use factories and builders in your unit tests. I learned that one when about 40 tests needed a constructor call updated after an API change...

  • Just as importantly, use the front door first. Your tests should always use normal state if it's available. Only used interaction based testing when you have to (i.e. no state to verify against).

Anyway the gist of this is that I'd try to find out why/where the tests are breaking and go from there. Do your best to insulate yourself from change.


One of the benefits of unit testing is that when you make changes like this you can prove that you're not breaking your code. You do have to keep your tests in sync with your framework, but this rather mundane work is a lot easier than trying to figure out what broke when you refactored.


I would insists you to stick with the TDD. Try to check your Unit Testing framework do one RCA (Root Cause Analysis) with your team and identify the area.

Fix the unit testing code at suite level and do not change your code frequently specially the function names or other modules.

Would appreciate if you can share your case study well, then we can dig out more at the problem area?


Good question!

Designing good unit tests is hard as designing the software itself. This is rarely acknowledged by developers, so the result is often hastily-written unit tests that require maintenance whenever the system under test changes. So, part of the solution to your problem could be spending more time to improve the design of your unit tests.

I can recommend one great book that deserves its billing as The Design Patterns of Unit-Testing

HTH


If the problem is that your tests are getting out of date with the actual code, you could do one or both of:

  1. Train all developers to not pass code reviews that don't update unit tests.
  2. Set up an automatic test box that runs the full set of units tests after every check-in and emails those who break the build. (We used to think that that was just for the "big boys" but we used an open source package on a dedicated box.)

Well if the logic has changed in the code, and you have written tests for those pieces of code, I would assume the tests would need to be changed to check the new logic. Unit tests are supposed to be fairly simple code that tests the logic of your code.


Your unit tests are doing what they are supposed to do. Bring to the surface any breaks in behavior due to changes in the framework, immediate code or other external sources. What this is supposed to do is help you determine if the behavior did change and the unit tests need to be modified accordingly, or if a bug was introduced thus causing the unit test to fail and needs to be corrected.

Don't give up, while its frustrating now, the benefit will be realized.


I'm not sure about the specific issues that make it difficult to maintain tests for your code, but I can share some of my own experiences when I had similar issues with my tests breaking. I ultimately learned that the lack of testability was largely due to some design issues with the class under test:

  • Using concrete classes instead of interfaces
  • Using singletons
  • Calling lots of static methods for business logic and data access instead of interface methods

Because of this, I found that usually my tests were breaking - not because of a change in the class under test - but due to changes in other classes that the class under test was calling. In general, refactoring classes to ask for their data dependencies and testing with mock objects (EasyMock et al for Java) makes the testing much more focused and maintainable. I've really enjoyed some sites in particular on this topic:


Why should you have to change your unit tests every time you make changes to your framework? Shouldn't this be the other way around?

If you're using TDD, then you should first decide that your tests are testing the wrong behavior, and that they should instead verify that the desired behavior exists. Now that you've fixed your tests, your tests fail, and you have to go squish the bugs in your framework until your tests pass again.


Everything comes with price of course. At this early stage of development it's normal that a lot of unit tests have to be changed.

You might want to review some bits of your code to do more encapsulation, create less dependencies etc.

When you near production date, you'll be happy you have those tests, trust me :)


Aren't your unit tests too black-box oriented ? I mean ... let me take an example : suppose you are unit testing some sort of container, do you use the get() method of the container to verify a new item was actually stored, or do you manage to get an handle to the actual storage to retrieve the item directly where it is stored ? The later makes brittle tests : when you change the implementation, you're breaking the tests.

You should test against the interfaces, not the internal implementation.

And when you change the framework you'd better off trying to change the tests first, and then the framework.


I would suggest investing into a test automation tool. If you are using continuous integration you can make it work in tandem. There are tools aout there which will scan your codebase and will generate tests for you. Then will run them. Downside of this approach is that its too generic. Because in many cases unit test's purpose is to break the system. I have written numerous tests and yes I have to change them if the codebase changes.

There is a fine line with automation tool you would definatelly have better code coverage.

However, with a well wrttien develper based tests you will test system integrity as well.

Hope this helps.


If your code is really hard to test and the test code breaks or requires much effort to keep in sync, then you have a bigger problem.

Consider using the extract-method refactoring to yank out small blocks of code that do one thing and only one thing; without dependencies and write your tests to those small methods.


The extra code seems to have become a maintenance headache as when our internal Framework changes we have to go around and fix any unit tests that hang off it.

The alternative is that when your Framework changes, you don't test the changes. Or you don't test the Framework at all. Is that what you want?

You may try refactoring your Framework so that it is composed from smaller pieces that can be tested independently. Then when your Framework changes, you hope that either (a) fewer pieces change or (b) the changes are mostly in the ways in which the pieces are composed. Either way will get you better reuse of both code and tests. But real intellectual effort is involved; don't expect it to be easy.


I found that unless you use IoC / DI methodology that encourages writing very small classes, and follow Single Responsibility Principle religiously, the unit-tests end up testing interaction of multiple classes which makes them very complex and therefore fragile.

My point is, many of the novel software development techniques only work when used together. Particularly MVC, ORM, IoC, unit-testing and Mocking. The DDD (in the modern primitive sense) and TDD/BDD are more independent so you may use them or not.


Sometime designing the TDD tests launch questioning on the design of the application itself. Check if your classes have been well designed, your methods are only performing one thing a the time ... With good design it should be simple to write code to test simple method and classes.


I have been thinking about this topic myself. I'm very sold on the value of unit tests, but not on strict TDD. It seems to me that, up to a certain point, you may be doing exploratory programming where the way you have things divided up into classes/interfaces is going to need to change. If you've invested a lot of time in unit tests for the old class structure, that's increased inertia against refactoring, painful to discard that additional code, etc.

참고URL : https://stackoverflow.com/questions/920992/unit-test-adoption

반응형