게터와 세터에 대해 단위 테스트를 작성해야합니까?
게터와 세터에 대한 테스트를 작성해야합니까, 아니면 과잉입니까?
나는 아니오라고 말할 것입니다.
@Will은 100 % 코드 범위를 목표로 삼아야한다고 말했지만 위험한 견해입니다. 적용 범위가 100 % 인 단위 테스트를 작성할 수 있지만 전혀 테스트 할 수는 없습니다.
단위 테스트는 표현적이고 의미있는 방식으로 코드의 동작을 테스트하기 위해 제공되며 게터 / 세터는 끝의 수단 일뿐입니다. 테스트에서 getter / setter를 사용하여 "실제"기능을 테스트한다는 목표를 달성하면 충분합니다.
반면에, getter와 setter가 단지 get and set보다 더 많은 작업을 수행하는 경우 (즉, 적절하게 복잡한 방법이면) 테스트해야합니다. 그러나 단위 테스트 케이스를 작성하지 않는 단지 시간 낭비 게터 또는 세터를 테스트합니다.
TDD와 함께 울리는 YES
참고 :이 답변은 잠재적으로 나쁜 조언이기는하지만 계속 upvotes를 얻습니다. 이유를 이해하려면 아래의 여동생을 살펴보십시오 .
논란의 여지가 있지만, 나는이 질문에 '아니오'라고 대답하는 사람은 TDD의 기본 개념이 누락되었다고 주장합니다.
나를 위해, 대답은 울려 퍼지는이다 예 는 TDD를 수행합니다. 그렇지 않다면 그럴듯한 대답은 없습니다.
TDD의 DDD
TDD는 종종 주요 이점이 있다고 인용됩니다.
- 방어
- 코드가 변경 될 수 있지만 동작 은 변경 되지 않는지 확인하십시오 .
- 이것은 리팩토링의 매우 중요한 관행을 허용합니다 .
- 이 TDD를 얻거나 얻지 못합니다.
- 디자인
- 당신이 지정하는 일이 무엇을해야하는지, 그것을 작동하는 방법을 구현하기 전에 그것을.
- 이것은 종종 더 많은 정보에 근거한 구현 결정을 의미 합니다.
- 선적 서류 비치
- 테스트 스위트는 사양 (요구 사항) 문서 로 사용되어야합니다 .
- 그러한 목적으로 테스트를 사용한다는 것은 문서와 구현이 항상 일관된 상태임을 의미합니다. 하나를 변경하면 다른 것으로 변경됩니다. 별도의 워드 문서에서 요구 사항과 디자인을 유지하는 것과 비교하십시오.
구현과 별도의 책임
프로그래머로서, 속성을 중요성과 게터로 생각하고 일종의 오버 헤드로 세터를 생각하는 것은 대단히 유혹적입니다.
그러나 속성은 구현 세부 사항이며 세터와 게터는 실제로 프로그램을 작동시키는 계약 인터페이스입니다.
객체가 다음과 같이 철자를 작성하는 것이 훨씬 더 중요합니다.
클라이언트가 상태를 변경하도록 허용
과
클라이언트가 상태를 쿼리하도록 허용
그런 다음이 상태가 실제로 저장되는 방법 (속성이 가장 일반적이지만 유일한 방법은 아닙니다).
다음과 같은 테스트
(The Painter class) should store the provided colour
TDD 의 문서 부분에 중요합니다 .
테스트를 작성할 때 최종 구현이 사소한 (속성) 방어 이점 이 없다는 사실을 알 수 없습니다.
왕복 공학의 부족 ...
시스템 개발 세계의 주요 문제 중 하나는 왕복 공학 의 부족입니다. 1- 시스템의 개발 프로세스가 분리 된 하위 프로세스로 분할됩니다 (문서, 코드).
1 Brodie, Michael L. "John Mylopoulos : 개념적 모델링의 씨앗 봉제." 개념 모델링 : 기초 및 응용. Springer Berlin Heidelberg, 2009. 1-9.
... 그리고 TDD가이를 해결하는 방법
시스템 및 해당 코드의 스펙이 항상 일관되도록 TDD 의 문서 부분입니다.
먼저 디자인하고 나중에 구현
TDD 내에서 먼저 합격 합격 테스트를 작성한 다음 통과시키는 코드 만 작성하십시오.
높은 수준의 BDD 내에서 먼저 시나리오를 작성한 다음 통과시킵니다.
왜 세터와 게터를 제외시켜야합니까?
이론적으로 TDD 내에서 한 사람이 테스트를 작성하고 다른 사람이 테스트를 통과시키는 코드를 구현할 수 있습니다.
그러므로 스스로에게 물어보십시오 :
클래스 테스트를 작성하는 사람이 getter 및 setter를 언급해야합니다.
getter와 setter는 클래스에 대한 공용 인터페이스이므로 대답은 분명히 yes 이거나 객체의 상태를 설정하거나 쿼리 할 방법이 없습니다. 그러나이 작업을 수행하는 방법이 각 방법을 개별적으로 테스트하는 것은 아닙니다 . 자세한 내용은 다른 답변 을 참조하십시오.
분명히 코드를 먼저 작성하면 답이 명확하지 않을 수 있습니다.
Roy Osherove는 그의 유명한 저서 'The Art Of Unit Testing'에서 다음과 같이 말합니다.
속성 (Java의 getter / setter)은 일반적으로 로직을 포함하지 않으며 테스트 할 필요가없는 코드의 좋은 예입니다. 그러나 조심하십시오 : 일단 속성 내부에 검사를 추가하면 논리가 테스트되고 있는지 확인해야합니다.
TL; 박사 : 네 당신이 해야 하고, 함께 OpenPojo 사소한입니다.
게터와 세터에서 약간의 유효성 검사를 수행해야하므로 테스트해야합니다. 예를 들어,
setMom(Person p)
자신보다 어린 사람을 어머니로 설정해서는 안됩니다.Even if you aren't doing any of that now, odds are you will in the future, then this will be a good for regression analysis. If you want to allow setting mothers to
null
you should have a test for that should someone change that later on, this will reinforce your assumptions.A common bug is
void setFoo( Object foo ){ foo = foo; }
where it should bevoid setFoo( Object foo ){ this.foo = foo; }
. (In the first case thefoo
that is being written to is the parameter not thefoo
field on the object).If you are returning an array or collection you should be testing whether or not the getter is going to be performing defensive copies of the data passed into the setter before returning.
Otherwise, if you have the most basic setters/getters then unit-testing them will add maybe about 10 minutes at most per-object, so what is the loss? If you add behaviour you already have a skeleton test and you get this regression testing for free. If you are using Java, you have no excuse since there is OpenPojo. There are an existing set of rules you can enable and then scan your entire project with them to make sure they are applied consistently within your code.
From their examples:
final PojoValidator pojoValidator = new PojoValidator();
//create rules
pojoValidator.addRule( new NoPublicFieldsRule () );
pojoValidator.addRule( new NoPrimitivesRule () );
pojoValidator.addRule( new GetterMustExistRule () );
pojoValidator.addRule( new SetterMustExistRule () );
//create testers
pojoValidator.addTester( new DefaultValuesNullTester () );
pojoValidator.addTester( new SetterTester () );
pojoValidator.addTester( new GetterTester () );
//test all the classes
for( PojoClass pojoClass : PojoClassFactory.getPojoClasses( "net.initech.app", new FilterPackageInfo() ) )
pojoValidator.runValidation( pojoClass );
Yes, but not always in isolation
Allow me elaborate:
What is a unit test?
From Working effectively with legacy code1:
The term unit test has a long history in software development. Common to most conceptions of unit tests is the idea that they are tests in isolation of individual components of software. What are components? The definition varies, but in unit testing, we are usually concerned with the most atomic behavioral units of a system. In procedural code, the units are often functions. In object oriented code, the units are classes.
Note that with OOP, where you find getters and setters, the unit is the class, not necessarily individual methods.
What is a good test?
All requirements and tests follow the form of Hoare logic:
{P} C {Q}
Where:
{P}
is the precondition (given)C
is the trigger condition (when){Q}
is the postcondition (then)
Then comes the maxim:
Test behaviour, not implementation
This means that you shouldn't test how C
achieves the post-condition, you should check that {Q}
is the result of C
.
When it comes to OOP, C
is a class. So you shouldn't test internal effects, only external effects.
Why not test bean getters and setters in isolation
Getters and setters may involve some logic, but so long this logic does not have external effect - making them bean accessors2) a test will have to look inside the object and by that not only violate encapsulation but also test for implementation.
So you shouldn't test bean getters and setters in isolation. This is bad:
Describe 'LineItem class'
Describe 'setVAT()'
it 'should store the VAT rate'
lineItem = new LineItem()
lineItem.setVAT( 0.5 )
expect( lineItem.vat ).toBe( 0.5 )
Although if setVAT
would throw an exception, a corresponding test would be appropriate since now there is an external effect.
How should you test getters and setters?
There is virtually no point changing the internal state of an object if such change has no effect on the outside, even if such effect comes later on.
So a test for setters and getters should be concerned with the external effect of these methods, not the internal ones.
For example:
Describe 'LineItem class'
Describe 'getGross()'
it 'should return the net time the VAT'
lineItem = new LineItem()
lineItem.setNet( 100 )
lineItem.setVAT( 0.5 )
expect( lineItem.getGross() ).toBe( 150 )
You may think to yourself:
Wait a sec, we are testing
getGross()
here notsetVAT()
.
But if setVAT()
malfunction that test should fail all the same.
1Feathers, M., 2004. Working effectively with legacy code. Prentice Hall Professional.
2Martin, R.C., 2009. Clean code: a handbook of agile software craftsmanship. Pearson Education.
While there are justified reasons for Properties, there's a common Object Oriented Design belief that exposing member state via Properties is bad design. Robert Martin's article on the Open Closed Principle expands upon this by stating that Properties encourage coupling and therefore limit the ability to close a class from modification -- if you modify the property, all consumers of the class will need to change as well. He qualifies that exposing member variables isn't necessarily bad design, it might just be poor style. However, if properties are read-only, there's less chance of abuse and side-effects.
The best approach I can provide for unit testing (and this may seem odd) is to make as many properties as possible protected or internal. This will prevent coupling while discouraging writing silly tests for getters and setters.
There are obvious reasons where read/write Properties should be used, such as ViewModel properties that are bound to input fields, etc.
More practically, unit tests should drive functionality through public methods. If the code you're testing happens to use those properties, you get code-coverage for free. If it turns out that these properties never get highlighted by code-coverage there's a very strong possibility that:
- You are missing tests that indirectly use the properties
- The properties are unused
If you write tests for getters and setters, you get a false sense of coverage and will not be able to determine if the properties are actually used by functional behavior.
If the cyclomatic complexity of the getter and/or setter is 1 (which they usually are), then the answer is no, you shouldn't.
So unless you have a SLA that requires 100% code-coverage, don't bother, and focus on testing the important aspect of your software.
P.S. Remember to differentiate getters and setters, even in languages like C# where properties might seem like the same thing. The setter complexity can be higher than the getter, and thus validate a unit-test.
A humorous, yet wise take: The Way of Testivus
"Write the test you can today"
Testing getters/setters may be overkill if you're an experienced tester and this is a small project. However, if you're just getting started learning how to unit test or these getters/setters may contain logic (like @ArtB's setMom()
example) then it would be a good idea to write tests.
This has actually been a recent topic between my team and I. We shoot for 80% code coverage. My team argues that getters and setters are auto implemented, and the compiler is generating some basic code behind the scenes. In this case, given the code generated is non-intrusive, it doesn't really make sense to test code the compiler creates for you. We also had this discussion about async methods and in that case the compiler generates a whole bunch of code behind the scenes. This is a different case and something we DO test. Long answer short, bring it up with your team and decide for yourselves if its worth testing.
Also, if you are using the code coverage report like us, one thing you can do is add the [ExcludeFromCodeCoverage] attribute. Our solution has been to use this for models that just have properties using getters and setters, or on the property itself. That way it won't affect the total code coverage % when the code coverage report is run, assuming that is what you are using to calculate your code coverage percentages. Happy testing!
In my opinion code coverage is a good way to see if you missed any functionality that you should cover.
When you inspect the coverage manually by it's pretty coloring then it can be argued that plain getters and setters do not need to be tested (although I always do).
When you only check the code coverage percentage on your project, then a test coverage percentage like 80% is meaningless. You can test all the none logical parts and forget some crucial parts. In this case only 100% means that you have tested all you vital code (and all the non-logical code as well). As soon as it is 99.9% you know that have forgotten something.
By the way: Code coverage is the final check to see if you have fully (unit) tested a class. But 100% code coverage not necessarily means that you have actually tested all the functionality of the class. So unit tests should always be implemented following the logic of the class. In the end you run coverage to see if you forgot anything. When you did it right, you hit 100% the first time.
One more thing: While recently working at a large bank in The Netherlands I noticed that Sonar indicated 100% code coverage. However, I knew something was missing. Inspecting the code coverage percentages per file it indicated a file at a lower percentage. The whole code base percentage was that large that the one file did not make the percentage be displayed as 99.9%. So you might want to look out for this...
I did a little analysis of the coverage achieved in the JUnit code itself.
One category of uncovered code is "too simple to test". This includes simple getters and setters, which the developers of JUnit do not test.
On the other hand, JUnit doesn't have any (non-deprecated) method longer than 3 lines that is not covered by any test.
I would say: YES Errors in getter/setter methods can silently sneak in and cause some ugly bugs.
I have written a lib to make this and some other tests easier. The only thing you have to write in your JUnit tests is this:
assertTrue(executor.execute(Example.class, Arrays.asList( new DefensiveCopyingCheck(),
new EmptyCollectionCheck(), new GetterIsSetterCheck(),
new HashcodeAndEqualsCheck(), new PublicVariableCheck())));
-> https://github.com/Mixermachine/base-test
Yes, especially if the item to get is an object of a class subclassed from an abstract class. Your IDE may or may not alert you that a certain property has not been initialized.
And then some apparently unrelated test crashes with a NullPointerException
and it takes you a while to figure out that a gettable property is actually not there to get in the first place.
Though that still wouldn't be anywhere as bad as discovering the problem in production.
It might be a good idea to make sure all your abstract classes have constructors. If not, the test of a getter might alert you to a problem there.
As for getters and setters of primitives, the question might be: Am I testing my program or am I testing the JVM or CLR? Generally speaking, the JVM does not need to be tested.
참고URL : https://stackoverflow.com/questions/6197370/should-unit-tests-be-written-for-getter-and-setters
'Programing' 카테고리의 다른 글
내 JS 파일 캐싱 Chrome 중지 (0) | 2020.07.03 |
---|---|
Jackson 직렬화 : 빈 값 무시 (또는 null) (0) | 2020.07.03 |
깊은 null 검사, 더 좋은 방법이 있습니까? (0) | 2020.07.03 |
Bash에서 XML을 구문 분석하는 방법은 무엇입니까? (0) | 2020.07.03 |
numpy를 사용하여 두 배열의 모든 조합으로 구성된 배열 만들기 (0) | 2020.07.03 |