Programing

Private / Protected 메서드는 단위 테스트를 받아야합니까?

lottogame 2020. 10. 18. 08:20
반응형

Private / Protected 메서드는 단위 테스트를 받아야합니까?


TDD 개발에서 일반적으로 가장 먼저하는 일은 인터페이스를 만든 다음 해당 인터페이스에 대한 단위 테스트 작성을 시작하는 것입니다. TDD 프로세스를 진행함에 따라 인터페이스를 구현하는 클래스를 생성하고 어느 시점에서 유닛 테스트를 통과하게됩니다.

이제 내 질문은 인터페이스에 의해 노출 된 메서드 / 속성을 지원하기 위해 클래스에 작성해야 할 수있는 개인 및 보호 메서드에 대한 것입니다.

  • 클래스의 개인 메서드에 자체 단위 테스트가 있어야합니까?

  • 클래스의 보호 된 메서드에 자체 단위 테스트가 있어야합니까?

내 생각:

  • 특히 인터페이스에 코딩을하고 있기 때문에 보호 / 비공개 메서드는 블랙 박스이므로 걱정할 필요가 없습니다.

  • 인터페이스를 사용하고 있기 때문에 정의 된 계약이 인터페이스를 구현하는 다른 클래스에 의해 올바르게 구현되었는지 확인하기 위해 단위 테스트를 작성하고 있습니다. 따라서 다시 한 번 private / protected 메서드에 대해 걱정해서는 안되며 다음을 호출하는 단위 테스트를 통해 실행되어야합니다. 인터페이스에 의해 정의 된 메소드 / 속성.

  • 내 코드 커버리지에 보호 / 개인 메서드가 적중 된 것으로 표시되지 않으면 올바른 단위 테스트가 없거나 사용되지 않고 제거해야하는 코드가있는 것입니다.


아니요, 개인 또는 보호 방법을 테스트 할 생각은 없습니다. 클래스의 private 및 protected 메서드는 공용 인터페이스의 일부가 아니므로 공용 동작을 노출하지 않습니다. 일반적으로 이러한 메서드는 테스트를 녹색으로 설정 한 후 적용하는 리팩토링에 의해 생성됩니다.

따라서 이러한 개인 메서드는 공용 인터페이스의 동작을 주장하는 테스트에 의해 암시 적 으로 테스트됩니다.

좀 더 철학적 인 메모에서 메서드가 아니라 동작을 테스트하고 있음을 기억하십시오. 따라서 테스트중인 클래스가 수행 할 수있는 일련의 작업을 생각한다면 클래스가 예상대로 작동하는지 테스트하고 주장 할 수있는 한 클래스에서 내부적으로 구현하는 데 사용되는 개인 (및 보호 된) 메서드가 있는지 여부 그 행동은 무관합니다. 이러한 메서드는 공개 동작의 구현 세부 정보입니다.


나는 대부분의 포스터에 동의하지 않습니다.

가장 중요한 규칙은 다음과 같습니다. 작업 코드는 공개 / 보호 / 사설에 대한 이론적 규칙을 무시합니다.

코드를 철저히 테스트해야합니다. 공개 메소드에 대한 테스트를 작성하여 보호 / 비공개 메소드를 충분히 수행 할 수 있다면 좋습니다.

할 수 없다면 리팩토링하여 할 수 있도록하거나 보호 / 비공개 규칙을 구부립니다.

아이들에게 시험을 준 심리학자에 대한 멋진 이야기가 있습니다. 그는 각 어린이에게 밧줄이 달린 나무 판 두 개를 양 끝에주고 가능한 한 빨리 발을 바닥에 대지 않고 방을 건너도록 요청했습니다. 모든 아이들은 작은 스키처럼 보드를 각 보드에 한 발씩 밧줄로 잡고 바닥을 미끄러지 듯 사용했습니다. 그런 다음 그는 그들에게 똑같은 임무를 주었지만 보드는 하나만 사용했습니다. 그들은 단일 보드의 양쪽 끝에 1 피트 씩 바닥을 가로 질러 회전 / "걷습니다". 그리고 그들은 더 빠릅니다!

Java (또는 모든 언어)에 기능 (개인 / 보호 / 공개)이 있다고해서 사용하기 때문에 더 나은 코드를 작성한다는 의미는 아닙니다!

이제 항상 이러한 충돌을 최적화 / 최소화하는 방법이 있습니다. 대부분의 언어에서 메서드를 public 대신에 보호하고 동일한 패키지 (또는 기타)에 테스트 클래스를 넣을 수 있으며 메서드는 테스트에 사용할 수 있습니다. 다른 포스터에 설명 된대로 도움이 될 수있는 주석이 있습니다. 리플렉션을 사용하여 개인 메서드를 얻을 수 있습니다 (yuck).

맥락도 중요합니다. 외부 사용자가 사용할 API를 작성하는 경우 공개 / 개인이 더 중요합니다. 내부 프로젝트라면 누가 정말 신경 쓰나요?

그러나 하루가 끝나면 테스트 부족으로 인해 얼마나 많은 버그가 발생했는지 생각해보십시오. 그런 다음 "과도하게 보이는"방법으로 인해 발생한 버그 수를 비교합니다. 그 대답이 당신의 결정을 이끌어야합니다.


당신은 다음과 같이 썼습니다.

TDD 개발에서 일반적으로 가장 먼저하는 일은 인터페이스를 만든 다음 해당 인터페이스에 대한 단위 테스트 작성을 시작하는 것입니다. TDD 프로세스를 진행함에 따라 인터페이스를 구현하는 클래스를 생성하고 어느 시점에서 유닛 테스트를 통과하게됩니다.

BDD 언어로 다시 말씀 드리겠습니다 .

클래스가 가치있는 이유와 동작 방식을 설명 할 때 일반적으로 가장 먼저하는 일은 인터페이스 *를 통해 클래스를 사용하는 방법에 대한 예제를 만드는 것입니다. 원하는 동작을 추가하면 해당 값을 제공하는 클래스가 생성되고 어느 시점에서 예제가 작동합니다.

* 실제 Interface또는 단순히 클래스의 액세스 가능한 API 일 수 있습니다. 예 : Ruby에는 인터페이스가 없습니다.

이것이 개인 메서드를 테스트하지 않는 이유입니다. 테스트는 클래스를 사용하는 방법의 예이며 실제로 사용할 수 없기 때문입니다. 원하는 경우 개인 메서드의 책임을 공동 작업 클래스에 위임 한 다음 해당 도우미를 모의 / 스텁하는 것이 좋습니다.

보호 된 메서드를 사용하면 클래스를 확장하는 클래스가 특정 동작을 가져야하고 어떤 가치를 제공해야한다고 말합니다. 그런 다음 클래스의 확장을 사용하여 해당 동작을 보여줄 수 있습니다. 예를 들어, 순서가 지정된 컬렉션 클래스를 작성하는 경우 동일한 내용을 가진 두 개의 확장이 동등 함을 보여주고 있음을 보여줄 수 있습니다.

도움이 되었기를 바랍니다!


클래스에 대한 단위 테스트를 작성할 때 클래스의 기능이 공용 인터페이스의 메서드에서 직접 구현되는지 또는 일련의 전용 메서드에서 구현되는지 여부에 반드시 신경 쓰지 않아도됩니다. 그렇습니다. 개인 메서드를 테스트해야하지만 그렇게하기 위해 테스트 코드에서 직접 호출 할 필요는 없습니다 (개인 메서드를 직접 테스트하면 구현이 테스트에 밀접하게 연결되어 리팩토링이 불필요하게 어려워집니다).

보호 된 메서드는 클래스와 미래의 자식간에 서로 다른 계약을 형성하므로 계약이 잘 정의되고 실행되는지 확인하려면 공용 인터페이스와 비슷한 범위로 실제로 테스트해야합니다.


아니! 인터페이스 만 테스트하십시오.

TDD의 큰 이점 중 하나는 비공개 메서드를 구현하기로 선택한 방법에 관계없이 인터페이스가 작동하도록 보장하는 것입니다.


다른 사람들이 위에서 말한 것을 완료하면 보호 된 메서드는 일종의 인터페이스의 일부라고 말할 수 있습니다. 인터페이스를 고려할 때 모든 사람이 생각하는 경향이있는 구성 대신 상속에 노출 된 메서드 일뿐입니다.

메서드를 private 대신 보호 됨으로 표시하면 타사 코드에서 사용할 것으로 예상되므로 상속 및 구성을 위해 열려있는 공용 메서드에 의해 정의 된 일반 인터페이스에서 발생하는 것처럼 일종의 계약을 정의하고 테스트해야합니다. .


테스트를 작성하는 데는 두 가지 이유가 있습니다.

  1. 예상되는 동작 주장
  2. 행동 회귀 방지

취하기 (1) 예상되는 행동 주장 :

When you're asserting expected behavior, you want to make sure the code works as you think it should. This is effectively an automated way of doing your routine manual verification that any dev would perform when implementing any kind of code:

  • Did what I just write works?
  • Does this loop actually end?
  • Is it looping in the order I think it is?
  • Would this work for a null input?

Those are questions we all answer in our heads, and normally, we'd try to execute the code in our heads too, make sure it looks like it does work. For these cases, it is often useful to have the computer answer them in a definitive manner. So we write a unit test that assert it does. This gives us confidence in our code, helps us find defects early, and can even help actually implementing the code.

It's a good idea to do this wherever you feel is necessary. Any code that is a little tricky to understand, or is non trivial. Even trivial code could benefit from it. It's all about your own confidence. How often to do it and how far to go will depend on your own satisfaction. Stop when you can confidently answer Yes to: Are you sure this works?

For this kind of testing, you don't care about visibility, interfaces, or any of that, you only care about having working code. So yes, you would test private and protected methods if you felt they needed to be tested for you to answer Yes to the question.

The take on (2) Preventing regression of behavior:

Once you've got working code, you need to have a mechanism in place to protect this code from future damage. If nobody was to ever touch your source and your config ever again, you wouldn't need this, but in most cases, you or others will be touching the source and the configs of your software. This internal fiddling is highly likely to break your working code.

Mechanisms exist in most languages already as a way to protect against this damage. The visibility features are one mechanism. A private method is isolated, and hidden. Encapsulation is another mechanism, where you compartmentalize things, so that changing other compartments doesn't affect others.

The general mechanism for this is called: coding to boundary. By creating boundaries between parts of the code, you protect everything inside a boundary from things outside of it. The boundaries become the point of interaction, and the contract by which things interact.

This means that changes to a boundary, either by breaking it's interface, or breaking it's expected behavior, would damage and possibly break other boundaries which relied on it. That's why it's a good idea to have a unit test, that targets those boundaries and assert they don't change in semantic and in behavior.

This is your typical unit test, the one most everybody talks about when mentioning TDD or BDD. The point is to hardened the boundaries and protect them from change. You do not want to test private methods for this, because a private method is not a boundary. Protected methods are a restricted-boundary, and I would protect them. They aren't exposed to the world, but are still exposed to other compartments or "Units".

What to make of this?

As we've seen, there's a good reason to unit test public and protected methods, as to assert our interfaces don't change. And there's also good reason to test private methods, as to assert our implementation works. So should we unit test them all?

Yes and No.

Firstly: Test all methods that you feel you need a definitive proof that it works in most cases as to be able to be confident your code works, no matter the visibility. Then, disable those tests. They've done there job.

Lastly: Write tests for your boundaries. Have a unit test for each point that will be used by other units of your system. Make sure this test assert the semantic contract, method name, number of arguments, etc. And also make sure the test asserts the available behavior of the unit. Your test should demonstrate how to use the unit, and what the unit can do. Keep these tests enabled so that they run on every code push.

NOTE: The reason you disabled the first set of test is to allow refactoring work to occur. An active test is a code coupling. It prevents future modification of the code it's testing. You only want this for your interfaces and interaction contracts.


No, you shouldn't test private methods (how would you anyway without using something horrible like reflection). With protected methods it is slightly less obvious in C# you can make things protected internal and I think it is OK to do that to test derived classes that implement all of their functionality through template pattern methods.

But, in general, if you think that your public methods are doing too much then it is time to refactor your classes into more atomic classes and then test those clases.


I too agree with @kwbeam's answer about not testing private methods. However, an important point I'd like to highlight - protected methods ARE part of a class' exported API and hence MUST be tested.

Protected methods may not be publicly accessible but you definitely are providing a way for sub-classes to use/override them. Something outside the class can access them and hence you need to ensure that those protected members behave in an expected manner. So don't test private methods, but do test public and protected methods.

If you believe you have a private method which contains critical logic, I'd try to extract it out into a separate object, isolate it and provide a way to test its behavior.

Hope it helps!


If you are aiming high code coverage (I suggest you should), you should test your all methods regardless of they are private or protected.

Protected is a kind of different discussion point, but in summary, it should not be there at all. Either it breaks encapsulation on deployed code, or it forces you to inherit from that class, just to unit test it, even sometimes you do not need to inherit.

Just hiding a method to client (making private) does not give it to have privilege not to be audited. Therefore, they can be tested by public methods as mentioned before.


I agree with everyone else: The answer to your question is 'no'.

Indeed you are entirely correct with your approach and your thoughts, especially about code coverage.

I would also add that the question (and the answer 'no') also applies to public methods that you might introduce to classes.

  • If you add methods (public/protected or private) because they make a failing test pass, then you've more or less achieved the goal of TDD.
  • If you add methods (public/protected or private) because you just decide to, violating TDD, then your code coverage should catch these and you should be able to improve your process.

Also, for C++ (and I should think only for C++) I implement interfaces using private methods only, to indicate that the class should only be used via the interface it implements. It stops me mistakenly calling new methods added to my implementation from my tests


A good design means splitting the application into multiple testable units. After doing this, some units are exposed to the public API, but some others may not be. Also, the interaction points between exposed units and these "internal" units are also not a part of the pubic API.

I think once we have the identifiable unit, is would benefit from the unit tests, regardless if exposed via public API or not.

참고URL : https://stackoverflow.com/questions/5601730/should-private-protected-methods-be-under-unit-test

반응형