A method for dynamic instrumentation in java unit testing
By introducing dynamic instrumentation technology into Java unit testing and defining multiple point interfaces, the problem of insufficient coverage of existing testing methods under extreme conditions and complex scenarios is solved, and more comprehensive test coverage is achieved.
Patent Information
- Application Number
- CN202310089505.9
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2023-02-09
- Publication Date
- 2026-02-24
- Estimated Expiration
- 2043-02-09
AI Technical Summary
Existing Java unit testing methods cannot effectively handle the coupling between methods, especially under extreme testing conditions, multi-threaded scenarios, and process/service downtime scenarios. They cannot simulate specific testing conditions, resulting in incomplete test coverage.
Dynamic instrumentation technology is used to define general, replacement, and interrupt point interfaces by declaring and embedding points, and dynamically insert them into the test code. Different point implementations are provided according to the user's test scenario, covering more test scenarios.
It achieves flexible coverage of Java unit tests, effectively simulating extreme test conditions, multi-threaded scenarios, and process/service downtime scenarios, thus improving the comprehensiveness and flexibility of testing.
Smart Images

Figure CN116302966B_ABST
Abstract
Description
Technical Field
[0001] This invention belongs to the field of big data technology, and in particular relates to a method for dynamic instrumentation in Java unit testing. Background Technology
[0002] After Java code is written, the mainstream unit testing approach is to use the JUnit framework for unit testing.
[0003] However, during code testing, coupling between methods is inevitable. The method under test will inevitably call other methods to fulfill its functional requirements, and these called methods may not function correctly during testing for the following reasons:
[0004] 1. The method being called was developed by someone else and is not yet implemented; it is only an interface.
[0005] 2. The called method depends on the runtime environment, and the test environment cannot run it normally, such as network services, database services, etc.
[0006] If you want to test this method at this point, you need to bypass the non-runnable methods called internally and use mock methods to do so.
[0007] Common open-source mocking frameworks for Java include Mockito, JMock, and JMockit.
[0008] Current technologies cannot address the testing needs of the following three scenarios:
[0009] Scenario 1: Extreme testing conditions. A file is generated based on the current timestamp file. If the file already exists, the creation fails. However, because it's impossible to artificially create an existing file at the moment of creation, it's impossible to test the creation failure scenario. This prevents the user from realistically testing whether the execution result in this scenario meets their expectations. (Similar scenarios include, but are not limited to, extreme scenarios such as full disk, full memory, and full threads.)
[0010] Scenario 2: Simulation of two mutually exclusive conditions that cannot be simultaneously invoked by different threads in a multi-threaded scenario.
[0011] Scenario 3: When a task is halfway through execution, it is suddenly terminated (e.g., simulating a power outage or abnormal restart); existing technology cannot test whether a task that is halfway through execution can be restarted when the service is restarted. Summary of the Invention
[0012] The purpose of this invention is to provide a method for dynamic instrumentation in Java unit testing, which solves the technical problem of providing different point implementations based on different user test scenarios by declaring and embedding points.
[0013] To achieve the above objectives, the present invention adopts the following technical solution: a method for dynamic instrumentation in Java unit testing, comprising the following steps:
[0014] Step 1: Set up a code input module and a Java unit code test server. The user inputs the code to be tested in the code input module, and the code input module transmits the code to be tested to the Java unit code test server via the Internet.
[0015] In the Java unit code test server, a test code cache module, a declaration point module, and an embedding point module are established. The test code cache module obtains and stores the code to be tested.
[0016] Step 2: Define the name of the point interface in the point declaration module, where the point types include three categories: general point, replacement point, and interrupt point;
[0017] Define three types of point interfaces respectively;
[0018] Step 3: In the declaration point module, declare the tracking points. The specific steps are as follows:
[0019] Step S3-1: Obtain the global point map in memory and obtain the point list storing the points;
[0020] Step S3-2: Determine whether the user has enabled the dynamic instrumentation function: if not, do nothing and return; if enabled, proceed to step S3-3.
[0021] Step S3-3: Declare the embedded point at any location in the code to be tested and generate the point's keywords;
[0022] Step 4: In the embedding module, embed points in the code to be tested, specifically including the following steps:
[0023] Step S4-1: Obtain the global point map in memory;
[0024] Step S4-2: Determine whether the user has enabled the dynamic instrumentation function: if not, do nothing and return; if enabled, proceed to step S4-3.
[0025] Step S4-3: Combine the second-to-last class in the method stack when the dot declaration is called, the second-to-last method in the method stack when the dot declaration is called, the last class in the method stack when the dot declaration is called, the last method in the method stack when the dot declaration is called, and the operation name defined at the dot declaration as the key for querying;
[0026] Step S4-4: Based on the key of the point, retrieve the point list from the point graph and check if the point exists in the point list: if it does not exist, put the point into memory and execute step S4-5; if it exists, execute step S4-7.
[0027] Step S4-5: Retrieve the point list from the point graph using the point's keyword;
[0028] Step S4-6: Based on the number of times the point will be repeatedly buried, add the buried points to the point list in a loop;
[0029] Step S4-7: End of data embedding;
[0030] Step 5: Declare the point module to retrieve the point list from the point graph using the key of the point;
[0031] Step 6: Determine if the obtained point list is empty. If the point list is empty, return directly; otherwise, continue.
[0032] Step 7: Delete and retrieve a user-inserted point from the point list, and execute the point at the corresponding declaration.
[0033] Preferably, the methods corresponding to the three types of point interfaces defined specifically include:
[0034] The method corresponding to the point interface of the general point takes the list of parameters passed by the user when embedding the point as parameters, and executes the method when the point is called, which constructs a certain preset condition or throws any exception in the point.
[0035] The method corresponding to the replacement point interface takes the original return value of a method executed at the user declaration and the parameter list passed when the user declares the embedded point as parameters. When the point is called, the original return value is replaced.
[0036] The method corresponding to the interruptible point interface takes the parameter list passed in when the user declares the embedded point as a parameter. When the point is called, it determines whether interruption is needed based on the passed parameters. If interruption is needed, the first value of the returned list is true. The return value of the parameter list is whether to interrupt and whether early return affects the test code flow.
[0037] Preferably, when performing step 3, three methods are used to declare the embedded points according to the type of the points, specifically including:
[0038] Method 3-1: The method for declaring the embedding of general-purpose points specifically takes the number of times the <method stack> is retrieved upwards and the name of the point operation as parameters, executes at the declaration, searches for the matching point in memory and executes it;
[0039] Method 3-2: The method for declaring and embedding replacement points specifically takes the number of times the <method stack> is retrieved upwards, the operation name of the point, the original return value of a certain method executed at the declaration, and the list of parameters passed when declaring the embedding point as parameters. It is executed at the declaration, searching for matching points in memory and executing them.
[0040] Method 3-3: The method for declaring an embedded interrupt point specifically takes the number of times the <method stack> is retrieved upwards, the operation name of the point, and the parameter list passed when declaring the embedded point as parameters. It is executed at the declaration point, searches for a matching point in memory and executes it, and returns the execution result.
[0041] Preferably, in methods 3-1, 3-2, and 3-3, the keyword of the point is formed by combining the number of times the <method stack> is used with the operation name of the point, which is used to find the point at the declaration.
[0042] Preferably, the structure of the dot plot is as follows:
[0043] Map <String,ArrayList <iburyingpointtexception>>pointMap;
[0044] The map's key is used to store the key of a point, and the map's value is used to store a list of points, named pointList.
[0045] This invention provides a method for dynamic instrumentation in Java unit testing, addressing the technical problem of providing different point implementations based on different user test scenarios through declaration and insertion points. This invention offers comprehensive coverage; compared to JMockit, it can cover more test scenarios through instrumentation, including but not limited to constructing extreme test conditions, testing in multi-threaded scenarios, and testing process / service downtime. It is also more flexible, as JMockit's insertion point declaration position follows the business code rather than the unit test code. Attached Figure Description
[0046] Figure 1 This is a flowchart of the execution and invocation of the declaration after the embedding of a general point declaration is discovered during runtime on the code under test according to the present invention;
[0047] Figure 2 This is a flowchart illustrating how the embedded general-type point declaration is discovered during runtime of the code under test according to the present invention. Detailed Implementation
[0048] Terminology Explanation:
[0049] JUnit: JUnit is a regression testing framework. JUnit testing is programmer testing, also known as white-box testing, because the programmer knows how the software being tested performs its functions and what functions it performs. JUnit is a framework; by inheriting the TestCase class, you can use JUnit for unit testing.
[0050] Method: The smallest unit of code execution in a Java thread is a method. A method is similar to a function in C++. In Java, a method can call other methods and declare variables. The lifecycle of a method includes the start of the method, the execution of the method, and the end of the method / exception. In Java, methods belong to a class.
[0051] Interface: In the Java programming language, an interface is an abstract type, a collection of abstract methods. Interfaces are typically declared using the `interface` keyword. A class implements the abstract methods defined in an interface by inheriting from it.
[0052] Method call stack: The method call stack represents the behavior of the order in which methods are called. It identifies the order in which methods are called. For example, if the method method 'method1' of class1 calls class2.method2 during its execution, then the method call stack is represented as Class1.method1 (push onto stack) → Class2.method2 (push onto stack) → Class1.method1 (pop from stack).
[0053] Threads: Java processes run using threads. In addition to the main thread, Java can create a thread by inheriting the java.lang.Thread class and start the created thread using its start() method.
[0054] Agentlib is a Java language library used to transfer specific JAR files via the Java command-line argument `--agentlib` or through the Java Virtual Machine API.
[0055] The agentlib library is embedded into the Java Virtual Machine to gain access to the capabilities of java.lang.instrument.Instrumentation (Java encoder).
[0056] After successful implantation, when the Java process starts, it will provide the java.lang.instrument.Instrumentation (Java encoder) object as a parameter to the compiler receiving class configured in the agentlib configuration file.
[0057] Depend on Figures 1-2 The method for dynamic instrumentation in Java unit testing, as shown, includes the following steps:
[0058] Step 1: Set up a code input module and a Java unit code test server. The user inputs the code to be tested in the code input module, and the code input module transmits the code to be tested to the Java unit code test server via the Internet.
[0059] In the Java unit code test server, a test code cache module, a declaration point module, and an embedding point module are established. The test code cache module obtains and stores the code to be tested.
[0060] Step 2: Define the name of the point interface in the point declaration module, where the point types include three categories: general point, replacement point, and interrupt point;
[0061] Define three types of point interfaces respectively;
[0062] The methods corresponding to the three types of point interfaces defined specifically include:
[0063] The method corresponding to the point interface of the general point takes the list of parameters passed by the user when embedding the point as parameters, and executes the method when the point is called, which constructs a certain preset condition or throws any exception in the point.
[0064] The interface name for the general-purpose Point type is:
[0065] com.freez.utils.clazz.IBuryingPointTException;
[0066] This interface defines:
[0067] <T extends Exception> void buryingPointTException(Object...params)throws T method;
[0068] The parameter params is a list of parameters passed in by the user when declaring the point to be embedded. The execution semantics of this method are: when this point is called, the user can construct certain pre-defined conditions in the point, or throw any exception.
[0069] The method corresponding to the replacement point interface takes the original return value of a method executed at the user declaration and the parameter list passed when the user declares the embedded point as parameters. When the point is called, the original return value is replaced.
[0070] The interface name for the replacement point is:
[0071] com.freez.utils.clazz.IBuryingPointReplace;
[0072] This interface defines <t>The `T buryingPointReplace(T mainObject, Object...otherParams)` method takes `mainObject` as the original return value of a method declared by the user and `otherParams` as the list of parameters passed in when the point is buried. The semantics of this method are: when this point is called, the original return value can be replaced.
[0073] The method corresponding to the interruptible point interface takes the parameter list passed in when the user declares the embedded point as a parameter. When the point is called, it determines whether interruption is needed based on the passed parameters. If interruption is needed, the first value of the returned list is true. The return value of the parameter list is whether to interrupt and whether early return affects the test code flow.
[0074] The interface name for the interrupt type Point is:
[0075] com.freez.utils.clazz.IBuryingPointTerminate;
[0076] This interface defines the boolean[] terminate(Object...params) method. The parameter Params is the list of parameters passed in when the user declares the point to be embedded. The return value is whether to interrupt and whether early return will affect the test code flow. The execution semantics of this method are: when this point is called, it can determine whether to interrupt based on the passed parameters. If interruption is required, the first value of the list should be returned as true.
[0077] Step 3: In the declaration point module, declare the tracking points. The specific steps are as follows:
[0078] Step S3-1: Obtain the global point map in memory and obtain the point list storing the points;
[0079] Step S3-2: Determine whether the user has enabled the dynamic instrumentation function: if not, do nothing and return; if enabled, proceed to step S3-3.
[0080] Step S3-3: Declare the embedded point at any location in the code to be tested and generate the point's keywords;
[0081] Specifically, three methods are used to declare embedded points based on the type of point:
[0082] Method 3-1: The method for declaring the embedding of general-purpose points specifically takes the number of times the <method stack> is retrieved upwards and the name of the point operation as parameters, executes at the declaration, searches for the matching point in memory and executes it;
[0083] The method name for embedding general-purpose points is declared as:
[0084] public static void buryingPointTException(int maxDeep,String opt,Object[]params)throws Throwabl;
[0085] The parameter `maxDeep` is used to retrieve the number of times the method stack is ascended, and the parameter `opt` is used to define the operation name of the point. `maxDeep` and `opt` together form the storage key of the point, which is used to find the point at the declaration. The parameter `params` is the list of parameters passed in by the user when declaring the point. The method semantics are to find the matching point in memory at this declaration and execute it.
[0086] Method 3-2: The method for declaring and embedding replacement points specifically takes the number of times the <method stack> is retrieved upwards, the operation name of the point, the original return value of a certain method executed at the declaration, and the list of parameters passed when declaring the embedding point as parameters. It is executed at the declaration, searching for matching points in memory and executing them.
[0087] The method name for embedding replacement points is declared as:
[0088] public static <t>T buryingPointReplace(int maxDeep,String opt,TmainObject,Object[]otherParams);
[0089] The parameter `maxDeep` is used to retrieve the number of times the <method stack> is ascended, and the parameter `opt` is used to define the operation name of the point. `maxDeep` and `opt` together form the storage key of the point, which is used to find the point at the declaration. The parameter `mainObject` is the original return value of a method executed at the user declaration, and the parameter `params` is the list of parameters passed in when the point is embedded in the user declaration. The method semantics is to find the matching point in memory at this declaration and execute it.
[0090] Method 3-3: The method for declaring an embedded interrupt point specifically takes the number of times the <method stack> is retrieved upwards, the operation name of the point, and the parameter list passed when declaring the embedded point as parameters. It is executed at the declaration point, searches for a matching point in memory and executes it, and returns the execution result.
[0091] The method name for declaring the embedding of interrupt points is:
[0092] public static boolean[]buryingPointTerminate(int maxDeep,String opt,Object[]params);
[0093] The method has several parameters: maxDeep (the number of times the method stack is accessed), opt (the name of the operation), maxDeep and opt (the storage key for the point), params (the list of parameters passed in when the point is declared), and return value (the execution result of the point). The method semantics are: at this declaration, find the matching point in memory, execute it, and return the execution result.
[0094] Preferably, in methods 3-1, 3-2, and 3-3, the keyword of the point is formed by combining the number of times the <method stack> is used with the operation name of the point, which is used to find the point at the declaration.
[0095] Step 4: In the embedding module, embed points in the code to be tested, specifically including the following steps:
[0096] Step S4-1: Obtain the global point map in memory;
[0097] Step S4-2: Determine whether the user has enabled the dynamic instrumentation function: if not, do nothing and return; if enabled, proceed to step S4-3.
[0098] Step S4-3: Combine the second-to-last class in the method stack when the dot declaration is called, the second-to-last method in the method stack when the dot declaration is called, the last class in the method stack when the dot declaration is called, the last method in the method stack when the dot declaration is called, and the operation name defined at the dot declaration as the key for querying;
[0099] The method for embedding general-purpose points is called:
[0100] public static void addBuryingPointTException(Class<?>penultimateClass,String penultimateClassMethod,Class<?>lastClass,StringlastClassMethod,String opt,IBuryingPointTException buryingPoint,intaddCount);
[0101] The method consists of the following parameters: `penultimateClass` (the second-to-last class in the method stack when the point is declared), `penultimateClassMethod` (the second-to-last method in the method stack when the point is declared), `lastClassMethod` (the last class in the method stack when the point is declared), `lastClassMethod` (the last method in the method stack when the point is declared), and `opt` (the operation name defined in the point declaration). `penultimateClass`, `penultimateClassMethod`, `lastClass`, `lastClassMethod`, and `opt` together form the key for storing the point, used to retrieve the point at the declaration. The `buryingPoint` parameter is the implementation class of the passed-in generic point interface, and the `addCount` parameter is the number of times this point will be repeatedly buried. The method semantics are: to put the user's generic point into memory, awaiting execution at the corresponding declaration.
[0102] The method for embedding replacement points is called:
[0103] public static void addBuryingPointReplace(Class<?>penultimateClass,String penultimateClassMethod,Class<?>lastClass,String lastClassMethod,Stringopt,IBuryingPointReplace buryingPointReplace,int addCount);
[0104] The method consists of the following parameters: `penultimateClass` (the second-to-last class in the method stack when the point is declared), `penultimateClassMethod` (the second-to-last method in the method stack when the point is declared), `lastClassMethod` (the last class in the method stack when the point is declared), `lastClassMethod` (the last method in the method stack when the point is declared), and `opt` (the operation name defined in the point declaration). `penultimateClass`, `penultimateClassMethod`, `lastClass`, `lastClassMethod`, and `opt` together form the key for storing the point, used to retrieve the point at the declaration. The `buryingPointReplace` parameter is the implementation class of the replacement point interface passed in by the user, and the `addCount` parameter is the number of times this point will be repeatedly buried. The method semantics are: to put the user's replacement point into memory, awaiting execution at the corresponding declaration.
[0105] The method for embedding interruption points is called:
[0106] public static void addBuryingPointTerminate(Class<?>penultimateClass,String penultimateClassMethod,Class<?>lastClass,String lastClassMethod,Stringopt,IBuryingPointTerminate buryingPointTerminate,int addCount);
[0107] Here, the parameters are: `penultimateClass` (the second-to-last class in the method stack when the point is declared), `penultimateClassMethod` (the second-to-last method in the method stack when the point is declared), `lastClassMethod` (the last class in the method stack when the point is declared), `lastClassMethod` (the last method in the method stack when the point is declared), and `opt` (the operation name defined in the point declaration). `penultimateClass`, `penultimateClassMethod`, `lastClass`, `lastClassMethod`, and `opt` together form the key for storing the point, used to find the point at the declaration. The parameter `buryingPointTerminate` is the implementation class of the interrupt point interface passed in by the user, and the parameter `addCount` is the number of times this point will be repeatedly buried. The method semantics are: to put the user's interrupt point into memory, waiting for execution at the corresponding declaration.
[0108] Step S4-4: Based on the key of the point, retrieve the point list from the point graph and check if the point exists in the point list: if it does not exist, put the point into memory and execute step S4-5; if it exists, execute step S4-7.
[0109] Step S4-5: Retrieve the point list from the point graph using the point's keyword;
[0110] Step S4-6: Based on the number of times the point will be repeatedly buried, add the buried points to the point list in a loop;
[0111] Step S4-7: End of data embedding;
[0112] Step 5: Declare the point module to retrieve the point list from the point graph using the key of the point;
[0113] Step 6: Determine if the obtained point list is empty. If the point list is empty, return directly; otherwise, continue.
[0114] Step 7: Delete and retrieve a user-inserted point from the point list, and execute the point at the corresponding declaration.
[0115] The structure of the dot graph is as follows:
[0116] Map <String,ArrayList <iburyingpointtexception>>pointMap;
[0117] The map's key is used to store the key of a point, and the map's value is used to store a list of points, named pointList.
[0118] This invention provides a method for dynamic instrumentation in Java unit testing, addressing the technical problem of providing different point implementations based on different user test scenarios through declaration and insertion points. This invention offers comprehensive coverage; compared to JMockit, it can cover more test scenarios through instrumentation, including but not limited to constructing extreme test conditions, testing in multi-threaded scenarios, and testing process / service downtime. It is also more flexible, as JMockit's insertion point declaration position follows the business code rather than the unit test code.< / iburyingpointtexception> < / t> < / t> < / iburyingpointtexception>
Claims
1. A method for dynamic instrumentation in Java unit testing, characterized in that: Includes the following steps: Step 1: Set up a code input module and a Java unit code test server. The user inputs the code to be tested in the code input module, and the code input module transmits the code to be tested to the Java unit code test server via the Internet. In the Java unit code test server, a test code cache module, a declaration point module, and an embedding point module are established. The test code cache module obtains and stores the code to be tested. Step 2: Define the name of the point interface in the point declaration module, where the point types include three categories: general point, replacement point, and interrupt point; Define three types of point interfaces respectively; Step 3: In the declaration point module, declare the tracking points. The specific steps are as follows: Step S3-1: Obtain the global point map in memory and obtain the point list storing the points; Step S3-2: Determine whether the user has enabled the dynamic instrumentation function: if not, do nothing and return; if enabled, proceed to step S3-3. Step S3-3: Declare the embedded point at any location in the code to be tested and generate the point's keywords; Step 4: In the embedding module, embed points in the code to be tested, specifically including the following steps: Step S4-1: Obtain the global point map in memory; Step S4-2: Determine whether the user has enabled the dynamic instrumentation function: if not, do nothing and return; if enabled, proceed to step S4-3. Step S4-3: Combine the second-to-last class in the method stack when the dot declaration is called, the second-to-last method in the method stack when the dot declaration is called, the last class in the method stack when the dot declaration is called, the last method in the method stack when the dot declaration is called, and the operation name defined at the dot declaration as the key for querying; Step S4-4: Based on the key of the point, retrieve the point list from the point graph and check if the point exists in the point list: if it does not exist, put the point into memory and execute step S4-5; if it exists, execute step S4-7. Step S4-5: Retrieve the point list from the point graph using the point's keyword; Step S4-6: Based on the number of times the point will be repeatedly buried, add the buried points to the point list in a loop; Step S4-7: End of data embedding; Step 5: Declare the point module to retrieve the point list from the point graph using the key of the point; Step 6: Determine if the obtained point list is empty. If the point list is empty, return directly; otherwise, continue. Step 7: Delete and retrieve a user-inserted point from the point list, and execute the point at the corresponding declaration.
2. The method for dynamic instrumentation in Java unit testing as described in claim 1, characterized in that: The methods corresponding to the three types of point interfaces defined specifically include: The method corresponding to the point interface of the general point takes the list of parameters passed by the user when embedding the point as parameters, and executes the method when the point is called, which constructs a certain preset condition or throws any exception in the point. The method corresponding to the replacement point interface takes the original return value of a method executed at the user declaration and the parameter list passed when the user declares the embedded point as parameters. When the point is called, the original return value is replaced. The method corresponding to the point interface for interruptible points takes the parameter list passed in when the user declares the embedded point as a parameter. When the point is called, it determines whether interruption is needed based on the passed parameters. If interruption is needed, the first value of the returned list is true. The return value of the parameter list is whether to interrupt and whether early return affects the test code flow.
3. The method for dynamic instrumentation in Java unit testing as described in claim 1, characterized in that: When performing step 3, three methods are used to declare the embedded points based on the point type, specifically including: Method 3-1: The method for declaring the embedding of general-purpose points specifically takes the number of times the <method stack> is retrieved upwards and the name of the point operation as parameters, executes at the declaration, searches for the matching point in memory and executes it; Method 3-2: The method for declaring and embedding replacement points specifically takes the number of times the <method stack> is retrieved upwards, the operation name of the point, the original return value of a certain method executed at the declaration, and the list of parameters passed when declaring the embedding point as parameters. It is executed at the declaration, searching for matching points in memory and executing them. Method 3-3: The method for declaring an embedded interrupt point specifically takes the number of times the <method stack> is retrieved upwards, the operation name of the point, and the parameter list passed when declaring the embedded point as parameters. It is executed at the declaration point, searches for a matching point in memory and executes it, and returns the execution result.
4. The method for dynamic instrumentation in Java unit testing as described in claim 3, characterized in that: In methods 3-1, 3-2, and 3-3, the keyword for a point is formed by combining the number of times the <method stack> is passed and the operation name of the point, which is used to look up the point at the declaration.
5. The method for dynamic instrumentation in Java unit testing as described in claim 1, characterized in that: The structure of the dot graph is as follows: Map<String,ArrayList <iburyingpointtexception> >pointMap;< / iburyingpointtexception> The map's key is used to store the key of a point, and the map's value is used to store a list of points, named pointList.
Citation Information
Patent Citations
Mobile terminal information asset use behavior identification method for application program
CN113849785A
Program file detection method and device, storage medium and electronic equipment
CN115080426A