How to setup the environmental requirements for integration tests in golang? - go

I am new to golang and have two little projects started, where I got to the same problem.
One uses a MySQL database as a datastore and the other elasticsearch. How can I write tests which cover the code for that.
At first I’ve used a HashMapDatastore, but with that I can only test my handlers and business logic, but not the persistence layer (e.g. if the persisting and retrieving works as I expect in elasticsearch) (aka integration test).
So should I test if there is a blank database for testing?
How should I delete this db after each test? I’ve found an approach for this in the integration tests of docker/libcompose but it is relatively complex.
Is there a common approach for that? Testing if there is an elasticsearch with an empty index available and if not failing the tests with a good setupmessage?
Thanks

Related

Is it worth implementing service integration tests in Spring Boot application?

I have come accross multiple articles on integration testing on Spring Boot applications. Given that the application follows three layer pattern (Web Layer - Service Layer - Repository Layer) I have not seen a single article with integration testing the application up to just the service layer (ommiting the web layer) where all the business logic is contained. All of the integration tests seem like controller unit tests - mostly veryfing only request and response payloads, parameters etc.
What I would like however is to verify the business logic using service integration tests. Since the web layer is responsible only for taking the results from services and exchanging them with the client I think this makes much more sense. Such tests could also contain some database state verifications after running services to e.g. ensure that there are no detached leftovers.
Since I have never seen such a test, is it a good practice to implement one? If no, then why?
There is no one true proper way to test Spring applications. A general approach is as you described:
slices tests (#DataJpaTest, #WebMvcTest) etc for components that heavily rely on Spring
unit tests for domain classes and service layer
small amount of e2e tests (#SpringBootTest) to see if everything is working together properly
Spotify engineers on the other hand wrote how they don't do almost any unit testing and everything is covered with integration tests that covered with integration tests.
There is nothing stopping you from using #SpringBootTest and test your service layer with all underlying components. There are things you need to consider:
it is harder to prepare test data (or put system under certain state), as you need to put them into the database
you need to clean the database by yourself, as (#SpringBootTest) does not rollback transactions
it is harder to test edge cases
you need to mock external HTTP services with things like Wiremock - which is also harder than using regular Mockito
you need to take care of how many application contexts you create during tests - first that it's slow, second each application context will connect to the database, so you will create X connections per context and eventually you can reach limits of your database server.
This is borderline opinion-based, but still, I will share my take on this.
I usually follow Mike Cohn's original test pyramid such as depicted below.
The reason is that unit tests are not only easier to write but also faster and most likely cover much more than other more granular tests.
Then we come across the service or integration tests, the ones you mention in your question. They are usually harder to write simply because you are now testing the whole application and not only a single class and take longer to run. The benefit is that you are able to test a given scenario and most probably they do not require as much maintenance as the unit tests when you need to change something in your code.
However, and here comes the opinion part, I usually prefer to focus much more on writing good and extensive unit tests (but not too much on test coverage and more on what I expect from that class) than on fully-fledged integration tests. What I do like to do is take advantage of Spring Slice Tests which in the pyramid would be placed between the Unit Tests and the Service Tests. They allow you to focus on a specific class (a Controller for example) but they also allow you to test some integration with the underlying Spring Framework or infrastructure. This is for me the best of both worlds. You can still focus on a single class but also test some relevant components of your application. You can test your web layer with #WebMvcTest or #WebFluxTest (so that you can test JSON deserialization and serialization, bean validation, etc...), or you can focus on your persistence layer with #DataJpaTest, #JdbcTest or #DataMongoTest (so that you can test the actual persistence and retrieval of data).
Wrapping up, I usually write a bunch of Unit Tests and then web layer tests to check my Controllers and also some persistence layer tests against a real database.
You can read more in the following interesting online resources:
https://martinfowler.com/articles/practical-test-pyramid.html
https://www.baeldung.com/spring-tests

Automate testing of caching functionality in a Spring Boot application

I am wondering about how can we testing automate functionality.
I am working on a Spring Boot micro-service where we use a GemFire cache. Right now I am testing it manually for below scenarios:
Is the data purged correctly after TTL is reached
Retrieving the data from cache if object exists
So, I know we can have a separate service which calls the GemFire and making sure that the object exists in cache (for step2). But not really sure how can we automate testing for step1.
And the whole point I am wondering is do we really need a new service completely to test this as a overhead? Are there any tools / better approach for testing the functionality?
Since you're using spring-boot and VMware GemFire together, I really hope you're taking advantage of the huge help and functionality spring-boot-data-gemfire provides out of the box. If you are, then you'd be delighted to know that there's yet another project, spring-test-data-geode, which can be used to write Unit and Integration Tests when building Spring Data for Apache Geode & VMware GemFire applications, you should really give it a try as it greatly helps in managing the scope and lifecycle of mock VMware GemFire/Apache Geode objects, along with cleaning all resources used by real objects used during Integration Tests.
As a side note, if you're using the Data Expiration Functionality shipped out of the box with VMware GemFire, I really don't see an actual need (other than the peace of mind that comes with I've tested everything I could) to include custom tests within your testing suite, you should only test what you own. The functionality itself is thoroughly tested already as part of the VMware GemFire / Apache Geode project itself, and you can see some (certainly not all) examples of such tests in the following links: ExpirationDUnitTest, RegionExpirationDistributedTest, ReplicateEntryIdleExpirationDistributedTest.
Cheers.
I have had some success using TestContainers here is the code used to create the container and
a sample test. It works by executing gfsh commands on the container but is slow.

Start a springboot project for each test case

We are developing test cases for a micro service using Spring Boot. One of the requirement is that for each Junit test case we need to:
start the project
test a unit case and
then stop the project .
I feel this is an anti pattern, but this is the requirement.
I looked around internet but couldn't find a solution for the same. I was able to start a web server but it provided no response and this might be because the project is not assigned to the server.
Does anyone have any idea on how this can be achieved?
PS: We don't want to use Mockito
Before hand i want to make clear that this a very bad practice and should be avoided. This approach does not implement unit tests concept correctly because you are testing an entire system up, so JUnit wouldn't be the correct tool.
I pocked around and i don't seem to find a Runner that may be able to do this (does not surprise me although), the most similar Runner may be SpringJUnit4ClassRunner which provides you a complete Spring context in your test space, but won't go live with the application.
An approach i'd suggest if you really want to go with this is to use tools like REST Assured to do End-to-End API layer tests against the live application, but this implies that you have to find another way to start the app, and then point the REST Assured tests to that started app. Maybe a shell script that starts the app and then starts the REST Assured tests suits, then when the suit ends put down the server.
I highly suggest you to chat with your product/management teams to avoid this kind of stuff since the tests will take FOREVER to run and you will be polluting your local or remote DBs if you are persisting data or other systems through REST or SOAP calls.

Spring Boot Integration Test failes due to lucene lock when using Hibernate Search

In my Spring Boot 1.5.10.Final project I use Hibernate Search ORM 5.6.4.Final. It works fine except of the integration tests. There is one test class with several
test methods to test the search logic. If I run just this test class every things works fine. Spring Boot is starting and creates the index. If I run this test class
together with all other integration tests, every test class will throw an LockObtainFailedException and the Hibernate Search tests will fail.
org.apache.lucene.store.LockObtainFailedException: Lock held by this virtual machine: ...LieferantEntity\write.lock
at org.apache.lucene.store.NativeFSLockFactory.obtainFSLock(NativeFSLockFactory.java:127) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
at org.apache.lucene.store.FSLockFactory.obtainLock(FSLockFactory.java:41) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
at org.apache.lucene.store.BaseDirectory.obtainLock(BaseDirectory.java:45) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
at org.apache.lucene.index.IndexWriter.<init>(IndexWriter.java:776) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
at org.hibernate.search.backend.impl.lucene.IndexWriterHolder.createNewIndexWriter(IndexWriterHolder.java:126) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.IndexWriterHolder.getIndexWriter(IndexWriterHolder.java:92) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.AbstractWorkspaceImpl.getIndexWriter(AbstractWorkspaceImpl.java:117) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.AbstractWorkspaceImpl.getIndexWriterDelegate(AbstractWorkspaceImpl.java:203) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.LuceneBackendQueueTask.applyUpdates(LuceneBackendQueueTask.java:81) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.LuceneBackendQueueTask.run(LuceneBackendQueueTask.java:46) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.SyncWorkProcessor$Consumer.applyChangesets(SyncWorkProcessor.java:165) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.search.backend.impl.lucene.SyncWorkProcessor$Consumer.run(SyncWorkProcessor.java:151) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
I use the default settings. If I set exclusive_index_use to false, then it works without failure but then the test execution is very slow.
For me it seems the index is initialized during the startup of Spring Boot and interferes between the tests.
Is it possible to use Spring Boot integration tests with Hibernate Search in a way so that locks are cleanly released between tests?
Alternativly I'm looking for a way to disable the Hibernate Search indexing for all integration tests not making use of Hibernate Search
I also tried already the property near-real-time and different lock factories as native, simple and single without luck.
First: do not use exclusive_index_use unless you are a Lucene guru. It is dangerous and probably will not behave as you want.
Now that we got that out of the way... As far as I understand, you are trying to execute integration tests in parallel on the same machine. This means integration tests will probably compete for access to the exact same index, and will write to the same index. This could lead to unpredictable results if your tests perform conflicting writes (one test erasing a document added by another test, before that test has completed).
If you really need to perform tests in parallel, I would recommend to execute each test in an isolated environment:
Dedicated DB, or at least dedicated DB schema
Dedicated Lucene index
etc.
In the case of Hibernate Search, you will have to find a way to use a different physical index in each test execution.
There are two ways to do that:
Just for tests, do not store the indexes on the filesystem, but directly in the heap, by setting hibernate.search.backend.directory.type to local-heap (Hibernate Search 6+) or hibernate.search.default.directory_provider to local-heap (Hibernate Search 5 and below).
It's super easy to implement, but there are a few disadvantages you should be aware of:
your testing environment will not be exactly the same as your production environment anymore
indexes will be lost after the tests have finished executing, which may make post-mortem debugging challenging (you won't be able to use Luke to inspect the state of the indexes anymore)
if your integration tests store a lot of content in the index, you might get an OutOfMemoryError.
If the disadvantages of solution 1 are too much for you, you can continue using the filesystem to store the indexes, but use a different configuration for each test execution, setting the index base path (hibernate.search.backend.directory.root for Hibernate Search 6+, or hibernate.search.default.indexBase for Hibernate Search 5 and below) to some unique path for each test execution. You will have to find how to do that in Spring, but I would be suprised to learn it's not possible. Maybe Spring allows you to use interpolation in the properties, something like hibernate.search.backend.directory.root = /tmp/it/#{testName}?
See the documentation about directory configuration (here for Hibernate Search 6+, or here for Hibernate Search 5 for more information on how to configure index storage.

Junit test that persist in mysql

Is it possible to write junit test that persist in mysql using hibernate / jpa?
If so any example available?
I'm using spring/hibernate for my application
When you have real database connection I would not call your test unit test, but more like integration test. To be honest this kind of tests is not a good idea in most cases. It requires some maintenance (every time you have changes in db), and in most cases just tests if it is possible to connect do database (and save some simple object).
Focus on writing good tests for domain level classes. Simple database integration tests will only give you illusion of high quality application.
If you want to write an integration test that looks like a unit test, you could try Arquillian.
What Arquillian does is basically start an application container (Glassfish I think is the default), then it deploys your server-side application in the container and runs the tests against the just-deployed application.
What you write in the unit tests is really client code, so that what you are effectively running is an integration test (with a real database and all the services you would have in a real environment), just in a junit-like way.
They also have a specific tutorial for persistence testing.

Resources