Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1311 Add Mock Tests to assist with developing/testing REST API's locally. #1315

Closed
wants to merge 6 commits into from

Conversation

UmenR
Copy link
Member

@UmenR UmenR commented Jun 11, 2021

Hi, @nya-elimuai I have made the changes required to run a single unit test without the requirement of the test env REST API, Could you please check if the changes below work as expected in your machine as well,
I.e: If this unit test can be run on its own without having to start the server, And if this unit test is run along with others if we run mvn clean verify -P regression-testing-rest etc.

This code needs to be refactored but I just wanted to verify if what we are expecting is achieved before doing further refactoring.

@UmenR UmenR requested a review from a team as a code owner June 11, 2021 09:23
@UmenR UmenR requested review from jo-elimu, nya-elimu and Keerthi4308 and removed request for a team June 11, 2021 09:23
Copy link
Member

@nya-elimu nya-elimu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@UmenR This looks like a good way to simulate JSON response from the server, thank you 🙂

A suggestion: Instead of replacing the functional (live) REST API test, what if we leave those, and instead add integration tests as a separate layer?

That way, we will eventually have 4 types of test layers:

  1. Unit tests - JUnit (run during local development)
  2. Integration tests - JUnit/Mockito (run during local development)
  3. REST API tests - JUnit (run after deployment to test server)
  4. UI tests - Selenium (run after deployment to test server)

@UmenR
Copy link
Member Author

UmenR commented Jun 11, 2021

@UmenR This looks like a good way to simulate JSON response from the server, thank you

A suggestion: Instead of replacing the functional (live) REST API test, what if we leave those, and instead add integration tests as a separate layer?

That way, we will eventually have 4 types of test layers:

  1. Unit tests - JUnit (run during local development)
  2. Integration tests - JUnit/Mockito (run during local development)
  3. REST API tests - JUnit (run after deployment to test server)
  4. UI tests - Selenium (run after deployment to test server)

@nya-elimuai Cool! Sounds good, But I'm a bit confused about the first two points, Shouldn't we swap the first two points? As in for Unit tests we can Mock the external services(External APIs or data from DB) because typically unit tests shouldn't rely on external services/inputs and are focused more on the functionality of a particular block of code. I focused particularly on this because currently, for any new API that I add I will not be able to run any tests against them because the changes are not in the test env.

Then for integration tests, we can use both, eg: For GET type requests we can fetch them from the test env, And then for POST type of requests we can use Mockito. I've mainly focused on the REST APIs in this case but I might be missing the bigger picture here.

Also, one more question that I have is I currently don't understand how we have separated out the two layers, As in Unit tests and Integration tests. Could you clarify that as well? eg: what commands/procedures we are to run for both these cases. As far as I understand when we run mvn clean test jetty:run we run the integration tests along with starting the server, And then to run unit tests individually we can run them through the IDE once the server is started.

@nya-elimu
Copy link
Member

nya-elimu commented Jun 11, 2021

@UmenR Thanks for clarifying. Actually, I think we are on the same track already, just using different terms for the same things. 😉

So let me clarify by re-phrasing to "regression testing": When I wrote "integration testing", I was mainly thinking about "mocked integration testing". So it would look something like this:

Test Package Technology Command Build environment
Unit tests ai.elimu.util JUnit mvn test Development
Integration tests ai.elimu.dao JUnit & Mockito mvn test Development
Regression tests (REST API) ai.elimu.rest JUnit mvn verify -P regression-testing-rest Test server
Regression tests (UI) ai.elimu.selenium JUnit & Selenium mvn verify -P regression-testing-ui Test server

The mocked integration tests are running relatively quickly (within seconds), right? If so, it makes sense to alway include them as part of the developer's build process.

And we shouldn't mock server request/response data as part of the regression tests, since the regression tests rely on more realistic (live) test data from an actual database.

Maybe we could rename some of these concepts to make the separation more clear. The main idea so far has been to use "regression testing" for tests that verify that existing functionality still works on the test server.

@nya-elimu nya-elimu added the enhancement New feature or request label Jun 11, 2021
@UmenR
Copy link
Member Author

UmenR commented Jun 12, 2021

@nya-elimuai Thanks for clarifying!! Now I thinkk I understand what you meant by having a seperate layer 😄 , In that case, what I was thinking of was shifting the new tests(ones that use Mockito) to a new location under test maybe by adding a new dev folder(test.java.dev.ai) that follows the same structure as we have inside (test.java.ai),

test
    ├── java
    │   ├── dev
    │   │   └── ai
    │   │       ├── elimu

And then include that directory under the default <id>no-regression-testing</id> profile. So that those tests will also be run during current unit & integration tests(with reference to the table in your previous comment).

OR we can create a separate profile only for the tests within the new folder this way we don't make changes to the existing profiles, What do you think?

However, one issue that I have right now is that we would now have to write two tests[One using Mockito (for unit and integration) and the other that uses test env API(for regression)] which I think is inevitable in our case.

@nya-elimu
Copy link
Member

nya-elimu commented Jun 12, 2021

In that case, what I was thinking of was shifting the new tests(ones that use Mockito) to a new location under test maybe by adding a new dev folder(test.java.dev.ai) that follows the same structure as we have inside (test.java.ai),

@UmenR Yes, that sounds like a good refactoring. And maybe with numbering to clarify the order of each category of tests?:

  • tests_01_unit
  • tests_02_integration
  • tests_03_regression_rest
  • tests_04_regression_ui

OR we can create a separate profile only for the tests within the new folder this way we don't make changes to the existing profiles, What do you think?

From what I understand, the order of execution would not matter for the integration tests. Meaning that it's probably okay if both the smaller unit tests and the mocked integration tests are run within the same group (Maven profile). In the future, we might have to ensure that unit tests are executed before the integrations tests, but as of now I think they can all be categorized within the same test suite.


However, one issue that I have right now is that we would now have to write two tests[One using Mockito (for unit and integration) and the other that uses test env API(for regression)] which I think is inevitable in our case.

I understand that concern. Still, they would not be 100% identical because their underlying test data would be different, isn't that right?

@UmenR
Copy link
Member Author

UmenR commented Jun 19, 2021

@nya-elimuai ,

So I've moved the new TestCase that uses Mockito to a separate location which is, https://github.com/elimu-ai/webapp/blob/e0ef6ed44d72e590d44010602407a1ee84ac1c3e/src/test/java/dev/ai/elimu/rest/LetterToAllophoneMappingsControllerTest.java.

If the above looks alright I think I can revert all changes done to src/test/java/ai/elimu/rest/v2/crowdsource/LetterToAllophoneMappingsControllerTest.java. So that as before it will only contain the integration tests.

Next up I've added the TestSuit which includes the TestCase that uses Mockito And a TestSuit Runner that is responsible for running the test suit. However, I'm not entirely sure if this is what you meant by renaming the test suits? For this to work I need to change the current profiles to exclude all except for the TestSuiteRunner So that we can configure whatever TestCases to be included in the TestSuit and have them execute according to the profile. This means that we would have to add seperate TestSuits and Runners per each group of tests I.E Integration, Unit, etc.
Or did you simply mean we need to make changes directly on the profile itself(pom file) by specifying the includes and the excludes because as far as I understand this approach would also achieve the same result as above with fewer classes(minus the TestSuit classes and the TestSuitRunner classes).

@nya-elimu
Copy link
Member

@UmenR The branch is not compiling for me:

[ERROR] Errors: 
[ERROR]   LetterToAllophoneMappingsControllerTest.testGetRequest » ExceptionInInitializer
[INFO] 
[ERROR] Tests run: 60, Failures: 0, Errors: 1, Skipped: 2

Copy link
Member

@nya-elimu nya-elimu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@UmenR Could you please rename the title of the GitHub issue for this PR?: #1311

"Improve test cases" is too broad for me to understand what exactly this code change is for.

See https://github.com/elimu-ai/wiki/blob/master/CONTRIBUTING.md#how-to-implement-and-submit-your-work

Keep each commit small so that diffs are easy to read and understand for people looking at your code in the future. A pull request should always be focused to doing one thing, for example fixing a bug or adding a new feature, but not a mixture. Avoid large commits and pull requests which attempt to do too much at once, as this makes code review difficult.

And maybe you should create one GitHub issue for refactoring and another for adding a mock test? Because this feels like too many changes at once.

@UmenR
Copy link
Member Author

UmenR commented Jun 21, 2021

@nya-elimuai Agreed! this PR is trying to tackle multiple issues in one go. let me change the issue and the code in this PR to focus on adding the mock tests only so that it addresses the immediate issue I faced with testing new REST API endpoints, I shall open a new issue for dealing with refactoring the exiting tests later.

@UmenR The branch is not compiling for me:

I'll remove the irrelevant code first, and let you know, which should fix the issue.

@UmenR UmenR changed the title 1311 improve test cases 1311 Add Mock Tests to assist with developing/testing REST API's locally. Jun 21, 2021
Comment on lines +1 to +11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<import resource="file:src/main/webapp/WEB-INF/spring/applicationContext-jpa.xml"/>

<bean id="letterToAllophoneMappingsController"
class="ai.elimu.rest.v2.crowdsource.LetterToAllophoneMappingsController"/>
</beans>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is including this file a requirement for enabling the Spring mock (MockMvcRequestBuilders) functionality?

@@ -1,22 +1,21 @@
package dev.ai.elimu.rest;
package ai.elimu;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test should be placed in the same package as the class being tested (i.e. ai.elimu.rest.v2.content)?

public class LetterToAllophoneMappingsControllerTest {

@Mock
public class LetterToAllophoneMappingsControllerTest extends RestControllerTest{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file being tested is LetterToAllophoneMappingsRestController, right? If so, this test should probably be renamed to LetterToAllophoneMappingsRestControllerTest.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public class LetterToAllophoneMappingsControllerTest extends RestControllerTest{
public class LetterToAllophoneMappingsControllerTest extends RestControllerTest {

private LetterDao letterDao;

@Autowired
LetterToAllophoneMappingsController letterToAllophoneMappingsController;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace with LetterToAllophoneMappingsRestController?

List<LetterToAllophoneMapping> testList = new ArrayList<>();
testList.add(letterToAllophoneMapping);
Mockito.when(letterToAllophoneMappingDao.readAllOrderedByUsage()).thenReturn(testList);
public void setup() throws JsonProcessingException {Allophone allophone = new Allophone();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing line break after {

allophoneDao.create(allophone);

Letter letter = new Letter();
letter.setDiacritic(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The letter 'c' is not a diacritic, so should be set to false. However, false is the default value, so this line can be deleted.

testList.add(letterToAllophoneMapping);
Mockito.when(letterToAllophoneMappingDao.readAllOrderedByUsage()).thenReturn(testList);
public void setup() throws JsonProcessingException {Allophone allophone = new Allophone();
allophone.setValueIpa("ɛɛ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you would like to check some examples of existing Letter-to-Allophone mappings, see http://eng.elimu.ai/content/letter-to-allophone-mapping/list

@nya-elimu
Copy link
Member

Closing this PR due to inactivity.

@nya-elimu nya-elimu closed this Sep 10, 2021
@nya-elimu nya-elimu deleted the 1311_improve_test_cases branch July 8, 2024 12:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants