Unit Test JUnit 4

Source: Internet
Author: User
Tags testng

Unit Test Tool JUnit 4

This article mainly describes how to use the various features provided by JUnit 4 to carry out effective unit testing, and an example of how to use ANT to perform automated unit testing. This article assumes that the reader has some experience with Java development under Eclipse and understands the annotations (annotation) feature in Java 5.


Needless to tell, programmers are responsible for the code they write, and not only do you have to make sure that it works properly by compiling, but also to meet the needs and design expectations. Unit testing is one of the effective means of verifying that code behavior meets expectations. But there is no denying that testing is a dull and boring thing, and that testing over and over again is a daunting task. Fortunately, the Unit Test tool JUnit makes it all simple and artistic.

JUnit is the most well-known unit testing tool in the Java community. It was born in 1997 and was developed jointly by Erich Gamma and Kent Beck. Erich Gamma is one of the authors of the classic book Design Pattern: The foundation of reusable object-oriented software, and has a great contribution to Eclipse; Kent Beck is an expert and pioneer in extreme Programming (XP).

A perfectly formed. JUnit is designed to be very small, but it is very powerful. Martin Fowler so much about JUnit: in software development, there is never so much code that plays such an important role. It makes it much easier for developers to perform unit tests, especially if JUnit 4 uses annotations in Java 5 (annotation) to make testing easier.

Back to top of page

JUnit 4 First Experience

Before we begin to experience JUnit 4, we need support for the following software:

    • Eclipse: The most popular IDE, which fully integrates JUnit and supports JUnit 4 starting with version 3.2. Of course, JUnit does not depend on any IDE. You can download the latest version of Eclipse from http://www.eclipse.org/.
    • Ant: A Java-based open source build tool that allows you to get the latest version and rich documentation on http://ant.apache.org/. Ant is already integrated in eclipse, but at the time of writing this article, Eclipse uses a lower ant version (required 1.7 or later) and does not support JUnit 4 very well.
    • JUnit: Its official website is http://www.junit.org/. You can get the latest news about JUnit from above. If you use JUnit in Eclipse like this article, you don't have to download it anymore.

First, create a new Java engineering--cooljunit for our experience. What you need to do now is to open the Project Cooljunit's property page, select the Java Build Path sub-option, click the "Add Library ..." button, and in the "Add Library" dialog box that pops up, select JUnit (Figure 1 ) and click the "Finish" button after selecting version 4.1 on the next page. This introduces JUnit into the current project library.

Figure 1 Adding a JUnit library to a project note the version of the JDK

JUnit 4.1 is a version of Java 5-based upgrade that uses many of the new features in Tiger to simplify the way it was used. Because of this, it cannot be run directly on the jdk1.4.x version. If you need to use JUnit in the jdk1.4.x version, please use the 3.8.1 version.

Can you start writing unit tests? And so on ..., where do you plan to put the unit test code? Mixing it with the code being tested is obviously confusing because the unit test code does not appear in the final product. It is recommended that you create separate directories for the unit test code and the code being tested, and that the test code and the code being tested use the same package name. This ensures the separation of the code, while also ensuring the convenience of the search. In accordance with this principle, we add a new directory to the project Cooljunit root directory testsrc, and added it to the project source code directory (join the way shown in Figure 2).

Figure 2 Modifying the project source code directory

Now we have a JUnit best practice: Unit test Code and the same package as the code being tested, different directories.

Everything is ready to start experiencing how to use JUnit for unit testing. The following example is from the author's development Practice: The static method in tool class Worddealutil wordformat4db is designed to handle the translation of the Java object name to the database table name (you can get more detailed information in the code comments). The following is the approximate situation after the first encoding is complete:

Package com.ai92.cooljunit;  Import Java.util.regex.Matcher;  Import Java.util.regex.Pattern;  /**  * Format the contents of a string format such as name, address, etc. * or formatted tool class *  * @author Ai92 */public  class Worddealutil {  /**  * Will J Ava Object Name (capitalized in the first letter of each word) formatted according to the habit of database naming * formatted data is lowercase and uses underscores to split the name of the word *  * For example: EmployeeInfo after formatting becomes employee_info  *  * @param name  Java Object Name *  /public static string wordformat4db (string name) {  Pattern p = patte Rn.compile ("[A-z]");  Matcher m = p.matcher (name);  StringBuffer sb = new StringBuffer ();  while (M.find ()) {  m.appendreplacement (SB, "_" +m.group ());  }  Return M.appendtail (SB). ToString (). toLowerCase ();  }  }

Can it be executed as expected? Try writing the JUnit unit test code for it as follows:

Package com.ai92.cooljunit;  Import static org.junit.Assert.assertEquals;  Import Org.junit.Test;  public class Testworddealutil {  //test wordformat4db normal operation @Test public void Wordformat4dbnormal () {  String targe t = "EmployeeInfo";  String result = worddealutil.wordformat4db (target);  Assertequals ("Employee_info", result);  }  }

It's a common class! The test class Testworddealutil used the word "test" to start with a better distinction between the test class and the tested class. The test method Wordformat4dbnormal called to execute the test method worddealutil.wordformat4db to determine whether the result of the operation reached the desired effect of the design. It should be noted that the test method Wordformat4dbnormal needs to be written according to certain specifications:

    1. The test method must use the callout org.junit.Test adornment.
    2. The test method must be decorated with public void and cannot have any arguments.

The string to be processed in the test method is "EmployeeInfo" and, as designed, the result should be "Employee_info". Assertequals is one of a series of static assertion methods provided by JUnit that judge whether the test results are correct (in class Org.junit.Assert), and we use it to compare the execution result to the expected value "Employee_info". To determine if the test was successful.

See how the results work. Right-click on the test class and select Run as JUnit test in the pop-up menu. The results of the operation are as follows:

Figure 3 JUnit Run Success interface


Green progress bar prompts us to pass the test run. But it's too early to announce that the code passed the Unit test. Remember: Your unit test code is not meant to prove you are right, but to prove that you are not wrong. Therefore, the scope of the unit test should be comprehensive, such as the boundary value, normal values, errors are worth testing, the code may appear in the overall prediction of problems, and this is the demand analysis, detailed design aspects to be considered. Obviously, our tests have just begun, and we continue to add some tests for special cases:

 public class Testworddealutil {...//test null processing @Test public void Wordformat4dbnull () {STR  ing target = null;  String result = worddealutil.wordformat4db (target);  Assertnull (result);  }//test the processing of an empty string @Test public void Wordformat4dbempty () {String target = "";  String result = worddealutil.wordformat4db (target);  Assertequals ("", result);  }//test when the first letter is capitalized @Test public void Wordformat4dbegin () {String target = "EmployeeInfo";  String result = worddealutil.wordformat4db (target);  Assertequals ("Employee_info", result);  }//test the case when the tail letter is uppercase @Test public void Wordformat4dbend () {String target = "Employeeinfoa";  String result = worddealutil.wordformat4db (target);  Assertequals ("employee_info_a", result);  }//When testing multiple connected letters capitalized @Test public void Wordformat4dbtogether () {String target = "Employeeainfo";  String result = worddealutil.wordformat4db (target);  Assertequals ("Employee_a_info", result); }  }

Run the test again. Unfortunately, the JUnit run-time interface prompts us to have two test cases failing the test (Figure 4)-When the initial capitalization results in a deviation from the expected result, causing the test to fail (failure), and when the result of null processing is tested, the exception is thrown directly-the test error. Obviously, the code in the test does not deal with both the initial capitalization and the null, which are modified as follows:

Modified method wordformat4db  /**  * Format the Java object name (the first letter of each word) according to the habit of database naming * formatted data is lowercase, and uses underscores to split the named word * If the parameter name is  NULL, returns NULL  *  * For example: EmployeeInfo after formatting becomes employee_info  *  * @param name Java Object Name */public  static String wordformat4db (string name) {  if (name = = null) {  return null;  }  Pattern p = pattern.compile ("[A-z]");  Matcher m = p.matcher (name);  StringBuffer sb = new StringBuffer ();  while (M.find ()) {  if (M.start ()! = 0)  m.appendreplacement (SB, ("_" +m.group ()). toLowerCase ())  ;  Return M.appendtail (SB). ToString (). toLowerCase ();  }
Figure 4 JUnit Run Failure interface

JUnit divides test failures into two types: failure and error. Failure is usually caused by a failure of the assertion method used by the unit test, which indicates that a problem was found at the test point, and the error is caused by a code exception, which is a discovery other than the test intent, which may result from the error in the test code itself (the test code is also code and cannot be guaranteed to be completely defective). It could also be a hidden bug in the code being tested.

Please keep in mind!

Keep this one of the JUnit best practices in mind: test for any possible errors. Unit tests are not meant to prove that you are right, but to prove that you are not wrong.

Aha, run the test again, and the green bar reappears. With the more comprehensive unit tests for WORDDEALUTIL.WORDFORMAT4DB, the code is now fairly stable and can be used as part of the API for other modules.

Unconsciously we've done a unit test with JUnit pretty. You can see how the JUnit is lightweight, simple, and does not need to be studied at all, which allows you to focus more on more meaningful things--to write a complete and comprehensive unit test.

Back to top of page

JUnit deep

Of course, the functionality provided by JUnit is by no means simple, and in the next section we will see a lot of useful features in JUnit, and it's very helpful to have the flexibility to write unit test code.


What is Fixture? It refers to a series of common resources or data required to execute one or more test methods, such as a test environment, test data, and so on. As you write your unit tests, you'll find that most of the test methods need to do a lot of work before you actually test them--Fixture for design preparation. These matting processes tend to occupy much more code than the actual test code, and this ratio increases as the complexity of the test grows. When multiple test methods are required to do the same, the "bad taste" of repetitive code is spread out in the test code. This "bad taste" will stain your code and cause errors due to negligence, and some means should be used to eradicate it.

JUnit specifically provides a way to set up a common Fixture, and all test methods in the same test class can share it to initialize Fixture and logoff Fixture. As with the JUnit test method, the public Fixture is easy to set up, and you only need to:

    1. Use annotation org,junit. Before modifies the method used to initialize the Fixture.
    2. Use the annotation org.junit.After to decorate the method used to unregister the Fixture.
    3. Both methods are guaranteed to be decorated with public void and cannot have any arguments.

Following the three principles above, the code is written roughly like this:

Initialize the Fixture method @Before public void init () {...}  Unregister the Fixture method @After public void Destroy () {...}

Thus, before each test method executes, JUnit guarantees that the Init method has initialized the test environment ahead of time, and when this test method finishes executing, JUnit calls the Destroy method to unregister the test environment. Note that the execution of each test method triggers the setting of the public Fixture, meaning that the public Fixture setting method using annotation before or after decoration is method-level (Figure 5). This ensures that independent tests do not interfere with each other, lest other test code modify the test environment or test data to affect the accuracy of other test code.

Figure 5 Method level Fixture execution

However, this Fixture approach has attracted criticism because it is inefficient, especially when setting up Fixture is very time consuming (for example, setting up a database link). And for a test environment that does not change or test data, it does not affect the results of the test method execution, and there is no need to reset the Fixture for each test method. As a result, the class-level Fixture setting method is introduced in JUnit 4 and is written as follows:

    1. Use annotation org,junit. Beforeclass modifies the method used to initialize the Fixture.
    2. Use the annotation org.junit.AfterClass to decorate the method used to unregister the Fixture.
    3. Both methods are guaranteed to be decorated with public static void and cannot have any arguments.

The class-level Fixture performs the initialization only before all test methods in the test class are executed and executes the logoff method after all test method tests have completed (Figure 6). The code template is as follows:

Class-Level Fixture initialization method @BeforeClass public static void DbInit () {...}  Class-Level Fixture logoff method @AfterClass public static void Dbclose () {...}
Figure 6 Class-level Fixture execution exception and time test

There are two very useful parameters in note org.junit.Test: expected and timeout. The parameter expected indicates that the test method expects to throw the specified exception, and if the test is run without throwing the exception, JUnit will assume that the test did not pass. This provides the convenience of verifying that the tested method will throw a predetermined exception in the case of an error. For example, the method Supportdbchecker is used to check whether the database version used by the user is within the scope of the system's support, and if the user uses an unsupported database version, the runtime exception unsupporteddbversionexception is thrown. Test method Supportdbchecker The unit test method that throws the specified exception if the database version is not supported is generally as follows:

@Test (expected=unsupporteddbversionexception.class) public  void Unsupporteddbcheck () {...}

Note Another parameter of Org.junit.Test, timeout, specifies how long the maximum time the test method is allowed to run, and if the test method runs longer than the specified number of milliseconds, JUnit considers the test to be unsuccessful. This parameter is useful for performance testing. For example, if it takes more than 1 seconds to parse a custom XML document, the design of the XML structure needs to be reconsidered, and the unit test method can be written like this:

@Test (timeout=1000) public  void Selfxmlreader () {...}
Ignore test methods

JUnit provides annotations Org.junit.Ignore for temporarily ignoring a test method, because sometimes the test environment is limited and there is no guarantee that each test method will work correctly. For example, the following code indicates that JUnit ignores the test method Unsupporteddbcheck because there is no database link:

@ Ignore ("DB is Off")  @Test (expected=unsupporteddbversionexception.class) public  void Unsupporteddbcheck () { ...... }

But be careful. Note Org.junit.Ignore can only be used for temporary ignore tests, and if you need to ignore them forever, be sure to verify that the tested code no longer requires these test methods to avoid ignoring the necessary test points.

Test Runner

Another new concept arises-the Test runner, which is the responsibility of all the test methods in JUnit. JUnit provides the default test runner for unit tests, but JUnit does not restrict you from having to use the default runner. Instead, you can customize not only your own runner (all the runtimes are inherited from Org.junit.runner.Runner), but you can also specify a specific runner for each test class. Specifying the method is also straightforward, using annotation org.junit.runner.RunWith to explicitly declare the runner to be used on the test class:

@RunWith (customtestrunner.class) public  class Testworddealutil {...}

Obviously, if the test class does not explicitly declare which test runner to use, JUnit starts the default test runner to execute the test class (such as the Unit test code mentioned above). In general, the default test runner can handle the overwhelming majority of unit testing requirements, and explicitly declaring a Test runner is essential when you use some of the advanced features provided by JUnit, such as the two features that are about to be introduced, or when you customize JUnit testing for special needs.

Test suite

In the actual project, with the progress of the project, the Unit test class will be more and more, but until now we will only one single run test class, which in actual project practice is certainly not feasible. To solve this problem, JUnit provides a way to run the test class in batches, called a test suite. This allows you to perform only one or several test suites each time you need to verify the correctness of the system's functionality. The test suite is very simple to use, and you only need to follow these rules:

    1. Create an empty class as the entrance to the test suite.
    2. Use annotations Org.junit.runner.RunWith and org.junit.runners.Suite.SuiteClasses to decorate this empty class.
    3. Pass Org.junit.runners.Suite as a parameter into the annotation runwith to prompt JUnit to use the Suite runner for this class.
    4. Make an array of the test classes that you want to put into this test suite as parameters for the annotation suiteclasses.
    5. Ensure that the empty class is decorated with public and that there are exposed constructors that do not have any arguments.
Package com.ai92.cooljunit;  Import Org.junit.runner.RunWith;  Import Org.junit.runners.Suite; .../**  * Test class in the batch Test kit * @author Ai92 *  /@RunWith (suite.class)  @Suite. suiteclasses ({ Testworddealutil.class}) Public  class Runallutiltestssuite {  }

In the example code, we put the test class Testworddealutil mentioned earlier in the test suite runallutiltestssuite, run the test suite in Eclipse and see that the test class Testworddealutil is invoked to execute. The test suite can contain not only the basic test class, but also other test suites, so that the unit test code of different modules can be easily managed hierarchically. However, you must ensure that there are no loops between the test suites, otherwise endless loops will appear in front of you ....

Parametric testing

Take a look back at our example of the "JUnit first experience" cited in the bar. In order to ensure the rigor of unit testing, we have simulated different types of strings to test the processing capability of the method, so we write a lot of unit test methods. But these test methods are all the same: The code structure is the same, the difference is only the test data and expectations. Is there a better way to extract the same code structure from the test method, improve the reusability of the Code, and reduce the hassle of copying and pasting the code? There is no good workaround on previous versions of JUnit, and now you can use the parameterized tests provided by JUnit to address this problem.

It's a little cumbersome to write parameterized tests (which is, of course, relative to other features in JUnit):

    1. Specifies a special runner org.junit.runners.Parameterized for the test class that is preparing to use parameterized tests.
    2. Declare several variables for the test class, respectively, to hold the expected value and the data used for the test.
    3. For the test class, declare a public static method that uses the annotation org.junit.runners.Parameterized.Parameters to return a value of java.util.Collection, and initialize all parameter pairs that need to be tested in this method.
    4. Declare a public constructor with parameters for the test class and assign values to several variables declared in the second link.
    5. Write a test method that uses the defined variables as parameters for testing.

We re-engineered our unit test code according to this standard:

Package com.ai92.cooljunit; Import static org.junit.Assert.assertEquals; Import Java.util.Arrays; Import java.util.Collection; Import Org.junit.Test; Import Org.junit.runner.RunWith; Import org.junit.runners.Parameterized; Import Org.junit.runners.Parameterized.Parameters;             @RunWith (parameterized.class) public class Testworddealutilwithparam {private String expected;             Private String target; @Parameters public static Collection words () {return arrays.aslist (new object[][]{{"E                 Mployee_info "," EmployeeInfo "},//test general processing conditions {NULL, NULL},//handling when testing null      {"", ""},//When testing an empty string for processing conditions {"Employee_info", "EmployeeInfo"}, Test the case when the first letter is capitalized {"Employee_info_a", "Employeeinfoa"},//test when the tail letter is uppercase {"Employee_a_i         NFO "," Employeeainfo "}//test multiple connected letters capitalized when});  }              /**        * Parametric test Required constructor * @param expected desired test result, corresponding to the first parameter in the parameter set * @param target test data, corresponding to the second parameter in the parameter set             */Public Testworddealutilwithparam (string expected, string target) {this.expected = expected;         This.target = target; /** * Tests the conversion of the Java object name to the database name */@Test public void wordformat4db () {         Ertequals (expected, worddealutil.wordformat4db (target)); } }

Obviously, the code is thin. In static method words, we use a two-dimensional array to build the list of parameters required for testing, where the order in which elements in each array is placed is not required, as long as it is consistent with the order in the constructor. Now if you add another test case, you just need to include the appropriate array in the static method words, and no longer have to copy and paste out a new method.

Back to top of page

JUnit and Ant

As the project progresses, the scale of the project is constantly expanding, and in order to ensure the quality of the project, it is necessary to have a planned implementation of a comprehensive unit test. However, the test suite provided by JUnit is difficult to do because the number of unit test classes in the project is constantly increasing, the test suite is unable to dynamically identify the newly added unit test class, and the test suite needs to be modified manually, which is an easy to forget step, and a slight omission will affect the coverage of the overall unit test.

Of course there are a variety of ways to solve this problem, in which JUnit is used in conjunction with the build weapon Ant to easily solve this issue. ant--'s award-winning Java building tool. With its excellent ease-of-use, platform independence, and support for project automated testing and automated deployment, it has become an indispensable tool in many project building processes and has become a de facto standard. Ant has built-in support for JUnit, which provides two task:junit and Junitreport for performing JUnit unit tests and generating test results reports, respectively. Using these two tasks to write a build script, you can easily complete the task of each comprehensive unit test.

However, before using Ant to run JUnit, you need to make some configuration. Open the Eclipse preferences interface and choose the Ant-to-Runtime preference (see Figure 7) to add the JUnit 4.1 JAR file to the Global Entries settings item in the Classpath Tab. Remember to check to see if the ant version in the ant Home Entries Settings item is above 1.7.0, if not replace with the latest version of the ant JAR file.

Figure 7 Ant Runtime Preferences

The rest of the work is to write the Ant build script Build.xml. Although this process is a little cumbersome, but this is a once and for all things. Now let's put the test cases written earlier into the Ant build script and add the content for the project Cooljunit build script:

 <?xml version= "1.0"?> <!--============================================= Auto unittest task ai92 ==========================================-< Project Name= "Auto unittest task" default= "JUnit and Report" Basedir= "." > <property name= "output folder" value= "Bin"/> <property name= "src folder" value= "src"/> <property na  Me= "Test Folder" value= "Testsrc"/> <property name= "Report folder" value= "Report"/> <!------------ -------Target:test Report folder init------------------- -<target name= "Test init" > <mkdir dir= "${report folder}"/> </target> <!----------- ET name= "compile" > <javac srcdir= "${src folder}" destdir= "${outputFolder} "/> <echo>compilation complete!</echo> </target> <!------------------- Target:compile Test Cases-----------------------to---<target N Ame= "Test Compile" depends= "Test init" > <javac srcdir= "${test folder}" destdir= "${output folder}"/> &LT;ECHO&G T;test compilation complete!</echo> </target> <target name= "All compile" depends= "compile, test compile" > </target> <!--======================================== target:auto Test all test case and OUTP UT report file =====================================--<target name= "JUnit and report "depends=" all compile "> <junit printsummary=" on "fork=" true "showoutput=" true "> <classpath> <filese T dir= "Lib" includes= "**/*.jar"/> <pathelement path= "${output folder}"/> </classpath> <formatter Typ E= "xml"/> <batchtesT todir= "${report folder}" > <fileset dir= "${output folder}" > <include name= "**/test*.*"/> </fileset&  Gt  </batchtest> </junit> <junitreport todir= "${report folder}" > <fileset dir= "${report folder}" > <include name= "Test-*.xml"/> </fileset> <report format= "frames" todir= "${report folder}"/> </ju Nitreport> </target> </project>

The target JUnit report is the core of the Ant build script, and the other target provides a pre-service for its execution. Task JUnit looks for all class files named "Test" in the output directory and executes them. The Task Junitreport then generates a test report in HTML format (Figure 8) with the result of the execution, placed under "Reports folder".

Determine a naming style for the unit test class for the entire project. This is also very helpful for ANT to perform unit tests in bulk, not only for classification purposes, such as the test class in the previous example has a "test" heading, and the test suite ends with "suite" and so on.

Figure 8 test report generated by Junitreport

It's easy to perform a full unit test now, just run the Ant build script and you can go through all the processes and get a detailed test report. You can get the details of the use of each ant built-in task mentioned above in the Ant online Manual.

Back to top of page


As more and more developers begin to recognize and accept the idea of extreme programming (XP), the role of unit testing becomes increasingly important in software engineering. This article is intended to introduce you to the latest Unit test tool, JUnit 4, and how to create automated unit test scenarios in conjunction with IDE Eclipse and build tools Ant. You are also expected to be able to "infect" some good unit testing awareness through this article, because JUnit itself is just a tool, and its real advantage comes from its ideas and techniques.

Back to top of page

Description name size
The sample code for this article Cooljunit.zip KB
Reference Learning
    • JUnit 4 First glance (Elliotte Rusty Harold, DeveloperWorks, October 2005): Elliotte Rusty Harold unveiled the new framework of JUnit 4 for everyone.
    • Pursuit of code quality: JUnit 4 vs. TestNG (Andrew Glover, DeveloperWorks, September 2006): Andrew Glover explores the unique features of the two frameworks, and describes the TestNG's unique three advanced Test the feature.
    • TestNG makes Java unit testing a breeze (Filippo Diotalevi, DeveloperWorks, January 2005): TestNG is not only really powerful, innovative, scalable, flexible, it also shows Java Annotations (JDK 5 Interesting application of the important new features in. 0.
    • Notes in Tiger, part 1th: Adding metadata to Java code (Brett McLaughlin, DeveloperWorks, September 2004): This article explains why metadata is so useful, introduces you to comments in the Java language, and studies T Built-in comments for Iger.
    • Incremental development with Ant and JUnit (Malcolm Davis, DeveloperWorks, November 2000): This article illustrates the benefits of unit testing by using code samples, especially with the convenience of Ant and JUnit.
    • pursuing the Code Quality series (Andrew Glover, DeveloperWorks): In this series, Andrew Glover will focus on something that sometimes seems a bit cryptic about guaranteeing the quality of the code.
Access to products and technologies
    • Access to JUnit software and related information.
    • Get ANT software and related information.
    • Get the Eclipse software and related information.

Unit Test JUnit 4

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.