Testing Probabilistic API Interfaces: Methodology and Java Implementation

This article describes how to test probability‑based API features such as lotteries by statistically validating expected odds, detecting bugs through extreme probability cases, and accelerating execution with Java multithreading, illustrated with a complete Java test code example.

FunTester
FunTester
FunTester
Testing Probabilistic API Interfaces: Methodology and Java Implementation

During my work on interface testing, I was responsible for weekly activity APIs that involved probabilistic business logic such as lotteries, random rewards, and user segmentation. Because each single API call returns an unpredictable result, only large‑scale statistical analysis can determine whether the implementation matches the configured probabilities.

Using a slot‑machine‑style activity as an example, the requirement was that users spend a certain amount of gold to obtain one draw, with four configurable gift types and a configurable "no‑win" probability (the remainder of 100%). Each gift's probability is expressed in 1% units.

The test involved three endpoints: a draw API, a configuration‑retrieval API, and a personal‑activity‑detail API. I wrapped the three endpoints into Java methods, invoked them repeatedly, and aggregated the results. The test was completed within a day.

Two main challenges were addressed:

How to judge whether the business result meets expectations: For an event with a configured probability of 10%, we run 1 / (a²) tests where a is the probability granularity (1%). In this case, 10 000 draws are performed; if the observed count falls between 950 and 1 050, the actual probability is considered acceptable.

How to determine if a bug exists: By setting extreme probabilities (0% or 100%) and running enough tests (again using the 1 / (a²) formula), any deviation from the expected outcome immediately indicates a bug.

Because single‑threaded execution was too slow, I introduced multithreading: running different test cases in parallel to reduce overall test time, and also running the same test case concurrently, which required careful handling of thread‑safe data collection.

In summary, probabilistic API testing is best performed as a white‑box test with statistical validation, extreme‑case checks, and multithreaded execution to achieve reasonable test duration.

Below is the Java test code used (note that the original multithreaded class is no longer available):

package com.fission.najm.activity.before.workPractise;

import com.fission.najm.base.NajmBase;
import net.sf.json.JSONObject;
import org.apache.http.client.methods.HttpGet;

public class Tiger extends NajmBase {
  public long aa = getDate().getTime();
  public String url = "http://haahi.7najm.com/service/activity/v3/32";
  public String loginKey;
  public int pay = 4;
  public int freeType = 2;
  public static int feather; // 羽毛
  public static int addFeather; // 增加羽毛数
  public static int addGift; // 增加礼物数
  public static int times; // 次数
  public static int type; // 结果类型
  public static int giftId; // 礼物 id
  public static int code; // 礼物 id
  public static JSONObject gifts = new JSONObject();
  public static JSONObject types = new JSONObject();

  public Tiger() {
    this.loginKey = loginNajm(1);
  }

  public static void main(String[] args) {
    Tiger tigger = new Tiger();
    tigger.getUserInfo();
    outputLine();
    output(types);
    output(gifts);
    output(addFeather);
    output(times);
    testOver();
  }

  public JSONObject getUserInfo() {
    JSONObject args = new JSONObject();
    args.put("loginKey", loginKey);
    args.put("type", 1);
    HttpGet httpGet = getHttpGet(url, args);
    JSONObject response = getHttpResponseEntityByJson(httpGet);
    output(response);
    return response;
  }

  public JSONObject testLucky() {
    JSONObject args = new JSONObject();
    args.put("loginKey", loginKey);
    args.put("pay", pay);
    args.put("freeType", freeType); // 是否是免费1免费 2付费
    args.put("type", 2);
    HttpGet httpGet = getHttpGet(url, args);
    JSONObject response = getHttpResponseEntityByJson(httpGet);
    if (response != null && response.containsKey("dataInfo")) {
      feather = response.getJSONObject("dataInfo").getInt("feather");
      type = response.getJSONObject("dataInfo").getInt("type");
      giftId = response.getJSONObject("dataInfo").getInt("giftId");
    } else {
      feather = 0;
      type = 0;
      giftId = 0;
    }
    code = response.getInt("code");
    output(response);
    return response;
  }

  public JSONObject getLuckys() {
    JSONObject args = new JSONObject();
    args.put("loginKey", loginKey);
    args.put("type", 3);
    HttpGet httpGet = getHttpGet(url, args);
    JSONObject response = getHttpResponseEntityByJson(httpGet);
    return response;
  }

  public JSONObject refresh() {
    JSONObject args = new JSONObject();
    args.put("loginKey", loginKey);
    args.put("type", 4);
    HttpGet httpGet = getHttpGet(url, args);
    JSONObject response = getHttpResponseEntityByJson(httpGet);
    return response;
  }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamultithreadingAPI testingprobabilistic testing
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.