The background,

At present, there are many SDKS in the market that integrate various functions. Developers only need to call the API provided by THE SDK to realize some functions that are relatively complex to be implemented originally. They do not need to worry about how to communicate with the server or build their own back-end server. I think the SDK is in the spirit of “let the professionals do the professional things”, and it’s very convenient for developers to some extent.

I recently studied the interface testing of iOS SDK and summarized it. If there is something wrong, please don’t hesitate to correct it

Two, from the client to SDK interface testing several insights

  1. Know exactly what you’re testing. It has been through the IM class client to test the SDK interface call, and the execution results of many functions are very intuitive. For example: in the test to send a message to someone, from the client’s point of view, it is easy to determine whether the case passed or not, just look at the interface to see if there is a corresponding message. However, when I judged it from the perspective of SDK interface test, I was a bit blindsided and had no idea how to judge whether this case passed or not (please forgive me for being a young OC at that time). For the above problem, it can be divided into two steps: step1: use the corresponding development language to implement the “send message” process. Step2: check whether the message is successfully sent. First step by learning the basic knowledge of the OC can be achieved, and the second step need to know some common sense, and how to use the SDK for the client’s development, then added up this knowledge, learned that this process is that, as shown in the figure below: client calls the “send a message that interface”, to send this message to the server; The server processes the packet after receiving it and sends a packet back to the client after successful processing. This callback triggers the “message successfully sent” callback function of the client. In this callback, the client parses the server’s return packet. For example, if the return code is successfully parsed, the client renders the message sent on the UI, and the whole process is completed. Therefore, in this case, we need to pay attention to whether the corresponding callback is triggered after receiving the packet back from the server, and whether the data returned by the server is the same as you expected. Most of the functions of the client are implemented in this way (of course, the figure is the simplest way, and there are also complex situations, such as multiple callback trigger, callback triggered multiple times, etc.). Therefore, to do a good job in SDK interface test, it is necessary to prepare the knowledge of the corresponding development language, and understand the use of SDK. So try to use the SDK to develop a demo is the best!
  2. A shift in thinking about test case design. Client test cases from top to bottom to consider a lot of time, namely, from the aspect of the use of the user to design test case, at first when I was in the design of the interface test cases is by writing code to construct various scenarios to determine interface call is correct, but then found that ignores the interface itself, and should go to know about the internal interface code, Design some cases for the implementation of the interface, such as parameter checking, etc., in other words, the design of test cases with the bottom up part. At the same time, I have recently read @chenhengjie123’s interface test in the forum, which has benefited a lot. You can read it and won’t repeat it again. To be honest, I feel that SDK interface testing has a lot to learn from server interface testing to some extent (forgive me for being a rookie of server interface testing) ~
  3. Interface testing is not a panacea. Interface testing to a large extent can free our hands and reduce the burden of manual testing, but some tests still need to be completed by manual testing, such as some exceptions, weak network performance, network switching, etc., so we need to do: We will not do anything that can be done with THE SDK interface test, but we should not rely too much on the SDK interface test and ignore the overall test indicators.

Test Tips

3.1 Asynchronous test method

Asynchronous method is not as easy as the require method, in the article on the top of the diagram, when the server will be package is returned to the app, asynchronous function callback is triggered, this function does not block the thread, and when to be triggered depends entirely on the server back to the time interval, so when we test method of the class, We need to satisfy a scenario where the test case code finishes executing when our callback function is triggered. There are also many ways to test asynchronous functions, I used here is to give xctest framework provides’ expectationForNotification ‘and’ waitForExpectationsWithTimeout ‘function and ios notification center function to implement some functions, as shown in the following code:

- (void)testSendtextmessage{NSString *text=@" textMessage "; / / structure text message NIMSession * session = [NIMSession session: _advanceTeamWithSendMessage type: NIMSessionTypeTeam]; NIMMessage *message=[[NIMMessage alloc] init]; message.text=text; // Call the sending message API [_chatManager sendMessage: Message toSession:session error:nil]; / / to monitor the ios notification center if there is content for the 'SendMassageSuccess notification messages [self expectationForNotification: @ "SendMassageSuccess" object: nil handler:nil]; // The listening behavior lasts for a maximum of 60 seconds. After receiving the notification message within 60 seconds, the test execution ends immediately. Not under shows there is a problem within 60 s [self waitForExpectationsWithTimeout: 60 handler: nil]; } // async callback function - (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error SendMassageSuccess [[NSNotificationCenter defaultCenter] postNotificationName:@"SendMassageSuccess"  object:nil]; }Copy the code

As explained by the comments in the code, we do one thing in an asynchronous function, is sending a message to the ios notification center, and in the case of test code for the asynchronous notification messages do wait, and set a maximum timeout, in order to realize whether asynchronous function is triggered and server data back to the package is correct.

3.2 use opportunely the random

As A Tester, a lot of our work is to test the results of various scenarios as expected, and a set of parameter combinations is a test case. Switching to the INTERFACE test of SDK, we can avoid writing a test case with a combination of parameters in a more ingenious way, but achieve the same effect through the combination of loop and Random. For example, in my tests, I have a “create advanced group” interface that takes two parameters (for example, there are more parameters in practice) : Parameter 1- Permission to apply for the group (enumeration value 0- Permission to apply for the group, 1- permission to join the group only after the application is approved by the administrator), Parameter 2- permission to modify the group information (enumeration value 0- permission to modify only the group master, 1- permission to modify the group master and the administrator, 2- permission to modify all the group information). The most direct and violent method is to write 6 test cases with similar structure to ensure that the interface is OK, but this will cause a lot of code and redundancy. As the title says, we can use the feature of random to do some things. As shown below:

- (void)testCreateAdvancedTeam { NSString *userId = [[[NIMSDK sharedSDK] loginManager] currentAccount]; NSArray *users = @[userId]; NSMutableArray *teamIds = [NSMutableArray array]; // construct case for (NSInteger index = 0; index < 6; Index++) {NIMCreateTeamOption *option = [[NIMCreateTeamOption alloc] init]; JoinMode = arc4Random () % 2; joinMode = arc4random() % 2; // Create option.updateInfomode = arc4random() % 3; [[[NIMSDK sharedSDK] teamManager] createTeam: Option Users: Users Completion :^(NSError *error, NSString *teamId) {// Some code to determine the return result}]; }}Copy the code

Every time the code is doing cycle + randomly generated random parameter model to reduce the amount of code, strictly speaking is not a rigorous security, but if the parameter combination with 12 kinds of situation, one of the parameters are not randomly to the probability of each time is 1/12, and our test not only run a project code, may run many times, The probability of a parameter not being covered is very, very small.

3.3 public class

When writing test cases where scenarios are reused multiple times, such as sending an image message, we can encapsulate the construction of an image message into a common class rather than writing code that generates the image every time we use it. With the proliferation of test cases, you should have a variety of common classes in your test projects that allow you to implement a variety of test scenarios. So, as you get more test cases, your test common classes should get richer.

3.4. Test code coverage

When there is a certain amount of test code, you have to consider whether the test code I wrote is “good” or “bad.” You can’t simply measure the number of test cases or the number of test code, because it is likely that your test cases will have a large number of repeated tests. A more scientific way is to count the code coverage of the test project. There’s a section called ‘Code Coverage’ in apple’s official documentation about how to count code coverage, but you can see for yourself: D.

Iv. References

  • Zero Basic learning iOS development series
  • XCTest tests in action
  • Xctest official documentation
  • Some thoughts on interface testing
  • Get out of the iOS unit testing mess