통합 테스트에 필요한 데이터베이스 데이터 API 호출 또는 가져온 데이터를 사용하여 생성 되었습니까?
이 질문은 어느 정도 프로그래밍 언어에 구애받지 않습니다. 그러나 요즘에는 대부분 Java를 사용하므로 여기에서 예제를 그릴 것입니다. 또한 OOP 사례에 대해 생각하고 있으므로 메서드를 테스트하려면 해당 메서드 클래스의 인스턴스가 필요합니다.
단위 테스트 의 핵심 규칙 은 자율적이어야하며 종속성에서 클래스를 분리하여 달성 할 수 있다는 것입니다. 이를 수행하는 방법에는 여러 가지가 있으며 IoC를 사용하여 종속성을 주입하는지 (Java 세계에는 주입 기능을 제공하는 Spring, EJB3 및 기타 프레임 워크 / 플랫폼이 있음) 및 / 또는 객체를 모의 (Java의 경우 JMock 및 EasyMock )을 사용하여 테스트중인 클래스를 종속성에서 분리합니다.
서로 다른 클래스 *의 메서드 그룹을 테스트하고 이들이 잘 통합되어 있는지 확인해야하는 경우 통합 테스트를 작성 합니다 . 그리고 여기 내 질문이 있습니다!
- 적어도 웹 애플리케이션에서는 상태가 종종 데이터베이스에 유지됩니다. 단위 테스트와 동일한 도구를 사용하여 데이터베이스로부터 독립 할 수 있습니다. 그러나 내 겸손한 의견으로는 통합 테스트에 데이터베이스를 사용하지 않는 것이 너무 조롱하는 경우가 있다고 생각합니다 (그러나 동의하지 않아도됩니다. 데이터베이스를 전혀 사용하지 않는 것도 질문을 무관하게 만들기 때문에 유효한 대답입니다. ).
- 통합 테스트에 데이터베이스를 사용할 때 해당 데이터베이스를 데이터로 어떻게 채우나요? 두 가지 접근 방식을 볼 수 있습니다.
- 통합 테스트를위한 데이터베이스 콘텐츠를 저장하고 테스트를 시작하기 전에로드합니다. SQL 덤프로 저장되는 경우 데이터베이스 파일, XML 또는 기타 정보가 흥미로울 것입니다.
- API 호출로 필요한 데이터베이스 구조를 만듭니다. 이러한 호출은 테스트 코드에서 여러 메서드로 분할되어 각 메서드 가 실패 할 수 있습니다. 다른 테스트에 대한 종속성이있는 통합 테스트로 볼 수 있습니다.
테스트에 필요한 데이터베이스 데이터가 필요할 때 있는지 어떻게 확인하고 있습니까? 그리고 선택한 방법을 선택한 이유는 무엇입니까?
흥미로운 부분은 동기 부여 에 있기 때문에 동기 부여와 함께 대답 해주십시오 . "가장 좋은 방법입니다!"라고 말하는 것을 기억하십시오. 아닌 실제 동기 부여, 당신이 읽거나 누군가로부터 들었습니다 단지 다시 반복 뭔가. 이 경우 왜 그것이 모범 사례 인지 설명하십시오 .
* 기술적으로 정확하지 않더라도 동일한 클래스의 (동일하거나 다른) 인스턴스에서 다른 메서드를 호출하는 하나의 메서드를 단위 테스트 정의에 포함하고 있습니다. 저를 수정 하셔도되지만 부수적 인 문제로 유지합시다.
API 호출을 사용하여 테스트 데이터를 만드는 것을 선호합니다.
테스트를 시작할 때 빈 데이터베이스 (인 메모리 또는 프로덕션에서 사용되는 것과 동일)를 만들고 설치 스크립트를 실행하여 초기화 한 다음 데이터베이스에서 사용하는 테스트 데이터를 만듭니다. 테스트 데이터의 생성은 예를 들어 Object Mother 패턴을 사용하여 구성 할 수 있으므로 동일한 데이터를 여러 테스트에서 재사용 할 수 있습니다.
부작용없이 재현 가능한 테스트를 수행하기 위해 모든 테스트 전에 데이터베이스를 알려진 상태로 유지하려고합니다. 따라서 테스트가 종료되면 테스트 데이터베이스를 삭제하거나 트랜잭션을 롤백해야 이전 테스트가 통과했는지 실패했는지에 관계없이 다음 테스트에서 항상 동일한 방식으로 테스트 데이터를 다시 만들 수 있습니다.
데이터베이스 덤프 (또는 유사) 가져 오기를 피하는 이유는 테스트 데이터를 데이터베이스 스키마와 결합하기 때문입니다. 데이터베이스 스키마가 변경되면 테스트 데이터를 변경하거나 다시 만들어야하므로 수동 작업이 필요할 수 있습니다.
테스트 데이터가 코드에 지정되어 있으면 IDE의 리팩토링 도구를 사용할 수 있습니다. 데이터베이스 스키마에 영향을주는 변경을 수행하면 API 호출에도 영향을 미치므로 API를 사용하여 코드를 리팩토링해야합니다. 거의 동일한 노력으로 테스트 데이터 생성을 리팩토링 할 수도 있습니다. 특히 리팩토링을 자동화 할 수있는 경우 (이름 변경, 매개 변수 도입 등). 그러나 테스트가 데이터베이스 덤프에 의존하는 경우 API를 사용하는 코드를 리팩토링하는 것 외에도 데이터베이스 덤프를 수동으로 리팩토링해야합니다.
데이터베이스 통합 테스트와 관련된 또 다른 사항은 이전 데이터베이스 스키마에서 업그레이드가 제대로 작동하는지 테스트하는 것입니다. 이를 위해 Refactoring Databases : Evolutionary Database Design 또는이 기사 를 읽어 볼 수 있습니다 : http://martinfowler.com/articles/evodb.html
통합 테스트에서는 애플리케이션이 실제로 데이터베이스와 통신 할 수 있는지 확인해야하므로 실제 데이터베이스로 테스트해야합니다. 데이터베이스를 종속성으로 격리한다는 것은 데이터베이스가 제대로 배포되었는지, 스키마가 예상대로인지, 앱이 올바른 연결 문자열로 구성되었는지에 대한 실제 테스트를 연기한다는 것을 의미합니다. 프로덕션에 배포 할 때 이러한 문제를 발견하고 싶지 않습니다.
또한 미리 생성 된 데이터 세트와 빈 데이터 세트로 테스트하려고합니다. 앱이 기본 초기 데이터 만있는 빈 데이터베이스로 시작하고 데이터 생성 및 채우기를 시작하는 경로와 스트레스, 성능 및 테스트와 같은 테스트하려는 특정 조건을 대상으로하는 잘 정의 된 데이터 세트를 모두 테스트해야합니다. 곧.
또한 각 상태 이전에 데이터베이스가 잘 알려진 상태인지 확인하십시오. 통합 테스트간에 종속성을 갖고 싶지 않습니다.
DBUnit 을 사용 하여 데이터베이스의 레코드 스냅 샷을 만들고 XML 형식으로 저장했습니다. 그런 다음 내 단위 테스트 (데이터베이스가 필요할 때 통합 테스트라고 함)는 각 테스트를 시작할 때 XML 파일에서 지우고 복원 할 수 있습니다.
이것이 노력할만한 가치가 있는지 여부는 미정입니다. 한 가지 문제는 다른 테이블에 대한 종속성입니다. 우리는 정적 참조 테이블 만 남겨두고 요청 된 레코드와 함께 모든 하위 테이블을 감지하고 추출하는 몇 가지 도구를 구축했습니다. 통합 테스트 데이터베이스에서 모든 외래 키를 비활성화하라는 누군가의 권장 사항을 읽었습니다. 이렇게하면 데이터를 더 쉽게 준비 할 수 있지만 더 이상 테스트에서 참조 무결성 문제를 확인하지 않습니다.
또 다른 문제는 데이터베이스 스키마 변경입니다. 스냅 샷이 생성 된 이후 추가 된 열에 대한 기본값을 추가하는 몇 가지 도구를 작성했습니다.
분명히 이러한 테스트는 순수 단위 테스트보다 훨씬 느 렸습니다 .
개별 클래스에 대한 단위 테스트를 작성하기가 매우 어려운 일부 레거시 코드를 테스트하려는 경우이 접근 방식은 그만한 가치가 있습니다.
귀하의 질문은 실제로 두 가지 질문 인 것 같습니다. 테스트에서 데이터베이스 제외를 사용해야합니까? 언제 데이터베이스를 사용합니까? 그러면 데이터베이스에서 데이터를 어떻게 생성해야합니까?
가능하면 실제 데이터베이스를 사용하는 것을 선호합니다. 종종 CRUD 클래스의 쿼리 (SQL, HQL 등으로 작성 됨)는 실제 데이터베이스와 마주했을 때 놀라운 결과를 반환 할 수 있습니다. 이러한 문제를 조기에 해결하는 것이 좋습니다. 종종 개발자는 CRUD에 대한 매우 얇은 단위 테스트를 작성합니다. 가장 양성 사례 만 테스트합니다. 테스트에 실제 데이터베이스를 사용하면 알지 못했던 모든 종류의 코너 케이스를 테스트 할 수 있습니다.
다른 문제가있을 수 있습니다. 각 테스트 후에 데이터베이스를 알려진 상태로 되돌리려 고합니다. 내 현재 작업은 모든 DROP 문을 실행 한 다음 모든 테이블을 처음부터 완전히 다시 생성하여 데이터베이스를 핵으로 만듭니다. 이것은 Oracle에서는 매우 느리지 만 HSQLDB와 같은 메모리 내 데이터베이스를 사용하는 경우 매우 빠를 수 있습니다. Oracle 특정 문제를 해결해야 할 때 데이터베이스 URL과 드라이버 속성을 변경 한 다음 Oracle에 대해 실행하면됩니다. 이런 종류의 데이터베이스 이식성이 없다면 오라클은이 목적을 위해 특별히 사용할 수있는 일종의 데이터베이스 스냅 샷 기능도 가지고 있습니다. 전체 데이터베이스를 이전 상태로 롤백합니다. 다른 데이터베이스가 무엇인지 확신합니다.
데이터베이스에있는 데이터의 종류에 따라 API 또는로드 방식이 더 좋거나 나쁘게 작동 할 수 있습니다. 관계가 많은 고도로 구조화 된 데이터가있는 경우 API는 데이터 간의 관계를 명시 적으로 만들어 삶을 편하게 만듭니다. 테스트 데이터 세트를 만들 때 실수하기가 더 어렵습니다. 다른 포스터 리팩토링 도구에서 언급했듯이 데이터 구조의 일부 변경 사항을 자동으로 처리 할 수 있습니다. 종종 API 생성 테스트 데이터를 시나리오를 구성하는 것으로 생각하는 것이 유용하다고 생각합니다. 사용자 / 시스템이 X, YZ 단계를 완료하면 거기에서 테스트가 진행됩니다. 이러한 상태는 사용자가 사용하는 것과 동일한 API를 호출하는 프로그램을 작성할 수 있기 때문에 달성 될 수 있습니다.
Loading data becomes much more important when you need large volumes of data, you have few relations between within your data or there is consistency in the data that can not be expressed using APIs or standard relational mechanisms. At one job that at worked at my team was writing the reporting application for a large network packet inspection system. The volume of data was quite large for the time. In order to trigger a useful subset of test cases we really needed test data generated by the sniffers. This way correlations between the information about one protocol would correlate with information about another protocol. It was difficult to capture this in the API.
Most databases have tools to import and export delimited text files of tables. But often you only want subsets of them; making using data dumps more complicated. At my current job we need to take some dumps of actual data which gets generated by Matlab programs and stored in the database. We have tool which can dump a subset of the database data and then compare it with the "ground truth" for testing. It seems our extraction tools are being constantly modified.
Why are these two approaches defined as being exclusively?
I can't see any viable argument for not using pre-existing data sets, especially particular data that has caused problems in the past.
I can't see any viable argument for not programmatically extending that data with all the possible conditions that you can imagine causing problems and even a bit of random data for integration testing.
In modern agile approaches, Unit tests are where it really matters that the same tests are run each time. This is because unit tests are aimed not at finding bugs but at preserving the functionality of the app as it is developed, allowing the developer to refactor as needed.
Integration tests, on the other hand, are designed to find the bugs you did not expect. Running with some different data each time can even be good, in my opinion. You just have to make sure your test preserves the failing data if you get a failure. Remember, in formal integration testing, the application itself will be frozen except for bug fixes so your tests can be change to test for the maximum possible number and kinds of bugs. In integration, you can and should throw the kitchen sink at the app.
As others have noted, of course, all this naturally depends on the kind of application that you are developing and the kind of organization you are in, etc.
I generally use SQL scripts to fill the data in the scenario you discuss.
It's straight-forward and very easily repeatable.
I do both, depending on what I need to test:
I import static test data from SQL scripts or DB dumps. This data is used in object load (deserialization or object mapping) and in SQL query tests (when I want to know whether the code will return the correct result).
Plus, I usually have some backbone data (config, value to name lookup tables, etc). These are also loaded in this step. Note that this loading is a single test (along with creating the DB from scratch).
When I have code which modifies the DB (object -> DB), I usually run it against a living DB (in memory or a test instance somewhere). This is to ensure that the code works; not to create any large amount of rows. After the test, I rollback the transaction (following the rule that tests must not modify the global state).
Of course, there are exceptions to the rule:
- I also create large amount of rows in performance tests.
- Sometimes, I have to commit the result of a unit test (otherwise, the test would grow too big).
This will probably not answer all your questions, if any, but I made the decision in one project to do unit testing against the DB. I felt in my case that the DB structure needed testing too, i.e. did my DB design deliver what is needed for the application. Later in the project when I feel the DB structure is stable, I will probably move away from this.
To generate data I decided to create an external application that filled the DB with "random" data, I created a person-name and company-name generators etc.
The reason for doing this in an external program was: 1. I could rerun the tests on by test modified data, i.e. making sure my tests were able to run several times and the data modification made by the tests were valid modifications. 2. I could if needed, clean the DB and get a fresh start.
I agree that there are points of failure in this approach, but in my case since e.g. person generation was part of the business logic generating data for tests was actually testing that part too.
'Programing' 카테고리의 다른 글
생성자가 템플릿 인수를 추론 할 수없는 이유는 무엇입니까? (0) | 2020.12.13 |
---|---|
대기열 크기 제한 (0) | 2020.12.13 |
다중 통화 모범 사례 및 구현 (0) | 2020.12.13 |
Python (.T)의 구문 (0) | 2020.12.13 |
__dict__ 클래스가 매핑 프록시 인 이유는 무엇입니까? (0) | 2020.12.13 |