强大的静态分析:Parasoft BugDetective






2.50/5 (5投票s)
数据流分析可以早期轻松地检测出异常、资源泄漏和安全漏洞等关键运行时错误。它还可以检查自动化单元测试报告的异常是否是“真正的缺陷”。
引言
软件缺陷主要有三种类型
- 需求实现不当:软件的运行不符合预期,因为需求中定义的功能实现错误。
- 需求缺失或不完整:软件未执行必要的操作或未处理可行的场景,因为利益相关者/设计者未预见到此类功能的需求,未为其指定需求,或者开发人员未能实现指定的需求。
- 用户困惑:软件的设计方式使困惑的用户可以走上非预期的路径。
构建健壮的回归测试套是识别需求实现不当的最佳方法,而执行负面测试是识别用户困惑错误的最佳方法。然而,发现缺失的需求却很困难,因为不清楚要找什么。流程分析,即在不执行代码的情况下分析代码路径,是目前唯一已知的能引导您发现此类问题的自动化测试技术。例如,假设流程分析在 Java 应用程序中识别出了一个 NullPointerException
。如果您检查导致异常的路径,然后考虑在何种条件下程序会进入此问题的起点,您可能会发现遗漏了需求——例如,该异常可能由某种可行的但从未在设计/规划阶段预料到的情况引起。如果测试仅侧重于编写验证需求的测试,则不会注意到这类问题。
除了指出遗漏的需求外,流程分析还可以暴露应用程序中的构造问题和逻辑缺陷。它旨在作为全面的回归测试套的一部分使用,该套件还包括模式匹配静态分析、单元测试、HttpUnit 测试、容器内测试、模块测试和 API 测试,以及您用于验证软件的任何其他测试。自动且定期(例如,每 24 小时)运行完整的回归测试套——包括流程分析和所有其他测试——是确定代码修改/添加是否引入了新问题、破坏了现有功能或导致了意外副作用的最有效方法。
本文探讨了为何以及如何将流程分析添加到现有的测试策略中。在介绍流程分析的通用概念和好处之后,本文将解释如何使用 Parasoft BugDetective™ 技术执行流程分析,并演示如何将其应用于加强您的静态分析和单元测试工作。
静态代码流程分析 - 背景
在软件行业中,“静态代码分析”对不同的人意味着不同的东西。似乎有两种主要的静态分析方法:(1) 程序执行或基于流程的分析,以及 (2) 基于模式的分析。对于程序执行的支持者来说,静态分析意味着尝试逻辑地执行程序——有时是符号化地执行——以发现内存损坏、泄漏和异常等代码问题。这类测试在很大程度上侧重于在不创建测试用例的情况下识别代码问题。它为开发人员提供了“即时反馈”,使他们能够在代码刚完成且尚记忆犹新时快速修复桌面上的缺陷和安全漏洞——并阻止缺陷和漏洞进入软件开发过程的后期,因为在后期发现和修复它们的成本会高得多。
Parasoft 静态分析和 BugDetective 技术
Parasoft 的静态分析技术同时支持基于流程的静态分析和基于模式的静态分析。Parasoft 的基于流程的静态分析技术(称为 BugDetective)可以轻松地早期检测到运行时问题和应用程序不稳定(例如 Java 中的 NullPointerException
、SQL 和其他注入、资源泄漏以及低效的迭代器使用),涵盖了跨越多个方法、类或包的路径。Parasoft BugDetective 技术可在 Parasoft Jtest(用于 Java 代码)、C++test(用于 C 和 C++ 代码)和 .TEST(用于 .NET 代码)中使用。本文重点介绍 BugDetective 在 Jtest 中的实现,但相同的通用概念和原则适用于 BugDetective 的所有实现。
通过自动跟踪和模拟即使是最复杂的应用程序的执行路径——那些跨越多个方法、类和/或包,包含数十个序列调用的应用程序——BugDetective 可以暴露那些通过手动测试或审查发现极其困难和耗时,并且如果在运行时才发现的话修复成本呈指数级增长的缺陷。使用 BugDetective,开发人员可以查找、诊断和修复那些可能逃避基于模式的静态分析和/或单元测试的软件错误类别。在软件开发生命周期的早期暴露这些缺陷可以节省数小时的诊断和潜在的返工。
BugDetective 静态分析在 Parasoft Jtest 中有两个应用
- 它作为 Jtest 静态分析的一部分,用于识别代码中基于流程的缺陷,如上所述。
- 它与 Jtest 的单元测试配合使用,以验证单元测试中报告的异常是否真的可以由实际应用程序路径触发。
使用 BugDetective 的好处
使用 BugDetective,开发团队可以获得以下关键好处:
- 利用现有资源进行更全面的测试:BugDetective 通过允许您查找那些原本需要开发、执行和维护复杂测试用例才能发现的问题,来补充其他测试技术。BugDetective 检查程序中的各种分支可能性,提供一种难以通过传统测试实现的路径覆盖级别。结果是,BugDetective 经常能发现通常在测试中未覆盖到的罕见情况处理过程中的问题。此外,如果代码功能发生更改,您可以搜索修改版本中的缺陷,而无需更新或重新生成测试用例。
- 自动识别跨越多个类的缺陷:传统的自动化单元测试生成可帮助您识别类内的缺陷。这一点至关重要。大多数开发人员都对一个类进行了彻底的测试,纠正了所有明显的问题,集成了代码,但后来却遇到了问题,例如
NullPointerException
,诊断了几天才找出原因,因为它们是由一个晦涩或复杂的执行路径引起的,该路径跨越了多个方法甚至多个包。使用 BugDetective,相同的问题可以在几秒钟内识别出来。 - 专注于实际缺陷和误用:BugDetective 可以自动且有把握地识别数据依赖或流程依赖的缺陷。在大多数情况下,BugDetective 报告的违规行为表明实际的误用(而不是单元测试中可能报告的“可能/假设的”误用)。例如,如果源代码中有一个调用
strlen
并传递 null 值的方法,BugDetective 才会报告一个违规,但单元测试会通过将 null 传递给测试中的strlen
方法来报告问题。
public int strlen(String str)
{
return str.length();
}
实战中的 BugDetective
BugDetective 独特的静态分析方法可以确定应用程序的执行路径是否与“可疑行为”配置文件匹配,这些配置文件作为规则实现。对于找到的每个缺陷,分层流程路径会详细说明导致已识别缺陷的完整执行路径,最后是错误显现的确切代码行。为了减少诊断和纠正每个找到的问题所需的时间和精力,流程路径详细信息辅以丰富的注释(例如,NullPointerException
违规描述包含关于流程路径中每个点的变量为何包含 null 值的注释)。
为了使分析过程更灵活并根据您独特的项目需求量身定制,某些规则可以参数化。因此,BugDetective 甚至可以用于检测与使用非常具体的 API 相关的违规行为。
理解流程路径
在 Jtest GUI 中,每个 BugDetective 违规都由一个分层流程路径表示,该路径精确描述了导致已识别问题的代码。路径中的每个元素都是运行时执行的代码行。如果流程路径中有对方法的调用,表示该方法调用的元素是一个节点,其子节点表示被调用方法内的执行流程。执行路径的最终元素始终是错误显现的点。整个路径按顺序呈现,以解释为什么在最终点存在错误。

流程路径元素会用图标标记,以帮助解释异常处理行为。如果路径中对某个方法有调用,并且该方法在该路径上抛出异常,则对应于该方法调用的路径元素将用一个红球标记。这个红球表示流程将进入 catch 或 finally 块,而不是正常继续。
流程路径中的每个元素都有一个工具提示,描述与违规相关的变量。例如,NullPointerException
违规描述包含描述流程路径中每个点的变量为何包含 null 值的注释。要查看流程路径元素的工具提示,请将鼠标悬停在其上。

如果您想导航到与已报告执行路径相关的代码,请使用 Jtest 视图工具栏中的 **下一个违规元素** 和 **上一个违规元素** 按钮。
理解和访问违规源点和违规点
违规本身由具有两个标记点的执行路径表示:
- 违规源点:这是违规的“来源”。通常这是“坏数据”的来源。例如,在
NullPointerException
规则中,违规源点是 null 值的来源。 - 违规点:这是“坏数据”使用点,通常会导致程序中的错误。对于
NullPointerException
规则,这是具有 null 值的变量被解引用的点。
您可以通过右键单击已报告的违规(带有黄色感叹号图标的节点)并从快捷菜单中选择相应的命令(“显示违规源点”或“显示违规点”)来轻松访问违规源点和违规点。例如,“Null pointer exception”规则违规在快捷菜单中具有“显示违规源点(Null 赋值点)”和“显示违规点(NullPointerException 点)”命令,以帮助您理解为什么代码中可能发生异常。

运行 BugDetective 静态流程分析
在其主要应用中,BugDetective 可作为 Jtest 静态分析的一部分,静态模拟应用程序的执行路径,并通过分析这些路径来查找漏洞。分析的深度可以降低以加快分析速度,也可以提高以获得更全面和深入的分析。
为了更好地理解 BugDetective 流程分析可以暴露的缺陷类型,让我们考虑如何将 Jtest 的 BugDetective 分析应用于示例 Java 类。一个示例类包含一个可能是 null 的类实例字段(示例 1 – TestField
类),第二个示例类包含一个可能是 null 的本地变量(示例 2 – TestLocal
类)。这两个类都调用了一个 LocalHelper
类。目标是演示 BugDetective 如何处理 (1) 过程内调用,以及 (2) 过程间调用(a)在一个类内,以及(b)跨越类边界的调用。
这两个示例都包含相同缺陷的实例字段和本地变量变体。名为 falsePositive
的方法包含假阳性,名为 truePositive
的方法包含真阳性。
BugDetective 在两个示例文件中标记了以下缺陷:
方法名称 |
TestField.java |
TestLocal.java |
falsePositive1 |
X |
X |
falsePositive2 |
X |
X |
falsePositive3 |
X |
X |
falsePositive4 |
X |
X |
ifalsePositive1 |
X |
X |
truePositive1 |
√ |
√ |
truePositive2 |
√ |
√ |
truePositive3 |
√ |
√ |
truePositive4 |
√ |
√ |
truePositive5 |
√ |
√ |
truePositive6 |
√ |
√ |
itruePositive1 |
√ |
√ |
itruePositve2 |
√ |
√ |
itruePositive3 |
√ |
√ |
X 表示 Jtest BugDetective 未在该方法中报告违规,√ 表示 Jtest 已在该方法中报告违规。
示例 1
public class TestFields {
Object x;
TestFields(Object x) {
this.x = x;
}
int falsePositive1(int level) {
x = null;
if (level > 0)
x = new Object();
if (level > 4)
return x.hashCode();
return 0;
}
int truePositive1(int level) {
x = null;
if (level > 0)
x = new Object();
if (level < 4)
return x.hashCode();
return 0;
}
int falsePositive2(boolean b) {
x = null;
if (b)
x = new Object();
if (b)
return x.hashCode();
return 0;
}
int truePositive2(boolean b) {
x = null;
if (b)
x = new Object();
if (!b)
return x.hashCode();
return 0;
}
int falsePositive3(boolean b) {
Object y = null;
if (x != null)
y = new Object();
if (y != null)
return x.hashCode() + y.hashCode();
else
return 0;
}
int truePositive3(boolean b) {
Object y = null;
if (x != null)
y = new Object();
if (y != null)
return x.hashCode() + y.hashCode();
else
return x.hashCode();
}
int falsePositive4(boolean a, boolean b) {
x = null;
Object y = null;
if (a) x = "x";
if (b) y = "y";
if (y != null)
return x.hashCode() + y.hashCode();
else
return 0;
}
int truePositive4(boolean a, boolean b) {
x = null;
Object y = null;
if (a) x = "x";
if (b) y = "y";
if (y != null)
return x.hashCode() + y.hashCode();
else
return x.hashCode();
}
int truePositive5() {
if (x == null) return x.hashCode();
return 0;
}
int truePositive6() {
if (x == null) {
Object y = x;
return y.hashCode();
}
return 0;
}
int ifalsePositive1(boolean b) {
x = null;
if (!b)x = new Object();
return LocalHelper.helper1(x, b);
}
int itruePositive1(boolean b) {
x = null;
if (b) x = new Object();
return LocalHelper.helper1(x, b);
}
int itruePositive2() {
x = null;
return LocalHelper.helper2(x);
}
int itruePositive3(boolean b) {
x = null;
if (b) x = "x";
return LocalHelper.helper3(x);
}
}
示例 2
public class TestLocal {
int falsePositive1(int level) {
Object x = null;
if (level > 0)
x = new Object();
if (level > 4)
return x.hashCode();
return 0;
}
int truePositive1(int level) {
Object x = null;
if (level > 0)
x = new Object();
if (level < 4)
return x.hashCode();
return 0;
}
int falsePositive2(boolean b) {
Object x = null;
if (b)
x = new Object();
if (b)
return x.hashCode();
return 0;
}
int truePositive2(boolean b) {
Object x = null;
if (b)
x = new Object();
if (!b)
return x.hashCode();
return 0;
}
int falsePositive3(Object x, boolean b) {
Object y = null;
if (x != null)
y = new Object();
if (y != null)
return x.hashCode() + y.hashCode();
else
return 0;
}
int truePositive3(Object x, boolean b) {
Object y = null;
if (x != null)
y = new Object();
if (y != null)
return x.hashCode() + y.hashCode();
else
return x.hashCode();
}
int falsePositive4(boolean a, boolean b) {
Object x = null;
Object y = null;
if (a) x = "x";
if (b) y = "y";
if (y != null)
return x.hashCode() + y.hashCode();
else
return 0;
}
int truePositive4(boolean a, boolean b) {
Object x = null;
Object y = null;
if (a) x = "x";
if (b) y = "y";
if (y != null)
return x.hashCode() + y.hashCode();
else
return x.hashCode();
}
int truePositive5(Object x) {
if (x == null) {
return x.hashCode();
}
return 0;
}
int truePositive6(Object x) {
if (x == null) {
Object y = x;
return y.hashCode();
}
return 0;
}
int ifalsePositive1(boolean b) {
Object x = null;
if (!b) x = new Object();
return LocalHelper.helper1(x, b);
}
int itruePositive1(boolean b) {
Object x = null;
if (b) x = new Object();
return LocalHelper.helper1(x, b);
}
int itruePositive2() {
return LocalHelper.helper2(null);
}
int itruePositive3(boolean b) {
Object x = null;
if (b) x = "x";
return LocalHelper.helper3(x);
}
}
public class LocalHelper {
// Bug when x is null and b is false
public static int helper1(Object x, boolean b) {
if (b) return 0;
return x.hashCode();
}
public static int helper2(Object x) {
return x.hashCode();
}
public static int helper3(Object x) {
return x.hashCode();
}
}
仔细查看结果,您会发现 BugDetective 在这些示例中没有标记任何假阳性。在 Parasoft 开发 BugDetective 的过程中,我们的主要目标之一是确保噪音水平(关于报告假阳性的情况)最小化——即使这意味着报告的缺陷数量会减少。在这个特定的案例中,所有十个假阳性都没有被报告;这是一个非常好的结果,它表明了这种设计决策在 BugDetective 中的体现。
同样,BugDetective 认为 truePositive3
方法中的缺陷是假阳性,即使其他技术可能会将其报告为真正的错误。
考虑来自 TestFields
类的以下代码:
Object x; //NPE origin
TestFields(Object x) {
this.x = x;
}
int truePositive3(boolean b) {
Object y = null;
if (x != null)
y = new Object();
if (y != null)
return x.hashCode() + y.hashCode();
else
return x.hashCode(); //NPE
}
实例变量 x
最初初始化为 null,但在构造函数调用中会被重新赋值为参数 x
的值。
Jtest BugDetective 不会标记此违规,因为在模拟代码的执行路径时,它会在路径上看到一个潜在的违规点(标记为 //NPE
的行),但它看不到从违规源语句(标记为 //NPE origin
的行)到该行而无需经过构造函数。Jtest BugDetective 不会标记此违规,因为它没有在源代码中找到包含以下步骤序列的路径:
TestFields tf = new TestFields();
tf.truePositive3(true|false);
它也没有找到如下路径:
TestFields tf = new TestFields(null);
tf.truePositive3(true|false);
然而,假设将以下方法添加到 TestFields
类中:
void callerTruePositive3() {
TestFields tf = new TestFields(null);
tf.truePositive3(true);
}
Jtest BugDetective 现在会标记此违规,因为它看到了违规源点和违规点,以及将两者连接起来的代码路径。如果 callerTruePositive3
方法不在代码中,Jtest 将不会在 truePositive3
中标记违规,除非它假设字段 x
可能会是 null(而不是查找显式路径)。如果您为 Jtest BugDetective 的 Avoid NullPointerExceptions
规则启用了一个额外的配置选项,BugDetective 将会做出此假设并标记违规;但是,此选项默认未启用,因为它会标记我们认为是假阳性的内容。
此外,即使 BugDetective 默认不标记此违规,Jtest 的单元测试也会将此缺陷报告为单元测试缺陷;Jtest 自动生成的 truePositive3
方法的 JUnit 测试用例中存在与 callerTruePositive3
方法类似的代码。这将在下一节中讨论。
将 BugDetective 与 Jtest 单元测试结合使用
BugDetective 还可用于检查报告的异常是否真的可以由实际应用程序路径触发。如果 BugDetective 验证了已报告的异常,则其严重性级别会提高,并在 Jtest 视图中特别标记。这有助于用户确定已报告的异常是否为“真正的缺陷”。
如果您将 Jtest 配置为使用 BugDetective 验证异常,Jtest 将自动收集从测试用例执行中报告的运行时异常,然后使用 BugDetective 尝试确定它们是否真的会在代码执行时发生。
例如,假设您有一个应用程序 A,其中有一个模块 M
,其中有一个类 C
。还假设当 Jtest 为应用程序中的每个类自动生成单元测试用例时,Jtest 对类 C
的测试用例揭示了一些运行时异常。这些异常中的每一个都可能指示以下两种情况之一:
- 类
C
中存在缺陷,因为它应该能够正确处理测试用例提供的输入。 - 类
C
未设计为处理测试用例提供的数据,因此不应将该数据传递给它。
启用异常验证后,Jtest 可以区分这两类已报告的异常。这样,您就可以立即确定已报告的异常是否为真正的缺陷——而无需分析代码。
BugDetective 和 Jtest 单元测试之间的协作价值在以下四种场景中得到了强调:
- 如果 BugDetective 无法在实际代码中找到测试用例条件可能发生的路径,则会过滤掉单元测试报告的异常。同时,如果它能在代码中找到验证该异常的实际路径,它将提高单元测试报告异常的严重性。
- BugDetective 标记了一个假阳性,但该假阳性在单元测试期间由于缺乏确认性单元测试而被过滤掉。
- 单元测试指向代码中的可疑位置,并且 BugDetective(基于这些信息)对这些位置进行比常规 BugDetective 运行更彻底的分析。这使得 Jtest 能够比 BugDetective 单独检测到更多的缺陷。
BugDetective 找到的违规路径,它无法确定是否要报告(根据其启发式规则),但这些缺陷随后被报告出来,因为单元测试标记了相同的路径。
使用 BugDetective 验证的单元测试异常将在 Jtest 视图中以红色阴影标记,并且其严重性级别也会根据测试配置的 **Execution> Severities** 选项卡中指定的程度提高。这允许客户根据自己的环境和应用程序配置异常的报告。

BugDetective 验证的单元测试异常指向实际缺陷,应予以纠正。经过 BugDetective 检查但未验证的异常表明该类未设计为处理测试用例提供的数据,因此不应将该数据传递给该类。应添加契约以指定不允许此类数据。
BugDetective 提升单元测试报告的异常
示例 3
public class SimpleNeverHappenedAndNotAcknowledgeByBD {
private class Name {
String _name;
Name (String name) {
_name = name;
}
public String toString() {
return _name;
}
}
Name _objectName;
public String getName () {
return _objectName.toString();
}
void initialize (String name) {
_objectName = new Name (name);
}
/**
public static void main(String[] args) {
SimpleNeverHappenedAndNotAcknowledgeByBD obj =
new SimpleNeverHappenedAndNotAcknowledgeByBD();
System.out.println(obj.getName()); //NPE
} */
}
示例 3 展示了 BugDetective 如何提升单元测试报告的异常。首先,我们在示例 3 上运行了内置的“BugDetective”测试配置,然后运行了内置的“生成并执行单元测试”测试配置,然后运行了一个用户定义的、启用了 BugDetective 验证的“生成并执行单元测试”测试配置。
当 main()
方法中的代码被注释掉时,BugDetective 不会报告任何缺陷,因为代码中没有地方在调用 initialize()
之前调用 getName()
。
当使用内置的“生成并执行单元测试”测试配置执行单元测试时,Jtest 会报告一个 java.lang.NullPointerException
。导致 NullPointerException
的测试用例如下:
public void testGetName5() throws Throwable {
SimpleNeverHappenedAndNotAcknowledgeByBD testedObject =
new SimpleNeverHappenedAndNotAcknowledgeByBD();
String result = testedObject.getName();
// NullPointerException thrown
// at example.A.SimpleNeverHappenedAndNotAcknowledgeByBD.getName
(SimpleNeverHappenedAndNotAcknowledgeByBD.java:36)
// jtest_unverified
}
当使用启用了 BugDetective 验证的用户定义的“生成并执行单元测试”测试配置执行单元测试时,Jtest 会报告完全相同的结果。在这种情况下,这是预期中的。由于 BugDetective 在此示例中未找到任何违规路径,因此没有任何单元测试异常可以被提升。
现在,让我们用取消注释的 main()
方法重复相同的测试。BugDetective 单独报告在第 13 行有一个可能的 NullPointerException
,该行标记为 // NPE
。使用内置的“生成并执行单元测试”测试配置执行单元测试会生成另外两个测试用例——其中一个会导致另一个 NullPointerException
。下面列出了该测试用例。
public void testMain1() throws Throwable {
String[] strings = new String[] {};
SimpleNeverHappenedAndNotAcknowledgeByBD.main(strings);
// NullPointerException thrown
// at example.A.SimpleNeverHappenedAndNotAcknowledgeByBD.getName(
// SimpleNeverHappenedAndNotAcknowledgeByBD.java:36)
// at example.A.SimpleNeverHappenedAndNotAcknowledgeByBD.main(
// SimpleNeverHappenedAndNotAcknowledgeByBD.java:50)
// jtest_unverified
}
使用启用了 BugDetective 验证的用户定义的“生成并执行单元测试”测试配置运行单元测试确实会提高这两个报告 NullPointerExceptions
的单元测试用例的严重性。在这两种情况下,这是因为 BugDetective 找到了导致 NullPointerException
的实际路径。在大型代码库中,此提升过程通常会大大简化定位真正缺陷并相应地分配资源。
单元测试和 BugDetective 协同过滤 BugDetective 报告的异常
示例 4
public class BDBogusNotApprovedByUT {
private boolean B = true;
BDBogusNotApprovedByUT() {
B = false;
}
public void test() {
Object o = null;
if (B) {
o.toString(); //NPE
}
else {
// we should go into this method (violation search method analysis guide)
// CallFromAnotherFile.methodWithNpe(o);
}
}
}
有人可能会争论 BugDetective 过滤的价值,因为 BugDetective 已经在捕获这个 NullPointerException
了。因此,让我们看一个示例(示例 4),其中 BugDetective 单独报告了一个假阳性,但在 BugDetective 与单元测试协同工作时没有报告任何缺陷。
BugDetective 在第 17 行触发了一个警告,该行标记为 //NPE
。这是因为 BugDetective 知道字段 B 被设置为 true
,但它没有意识到默认构造函数在调用 test()
方法之前会将字段 B 设置为 false
。
单元测试本身不报告任何异常,因此启用了 BugDetective 验证的单元测试也不报告任何异常。因此,即使 BugDetective 单独报告了这个假阳性,当 BugDetective 与单元测试协同工作时,它也会被过滤掉。这是一个非常简单的例子,有人可能会声称这种情况应该得到修复。也许——但有很多可能性,BugDetective 的启发式规则可能会出错并报告假阳性。在这些情况下,单元测试可以成功地用于验证或过滤掉这些异常。
结论
BugDetective 提供的独特流程分析,可以帮助软件开发团队在不执行代码的情况下发现关键的运行时错误,并验证单元测试用例暴露的异常是否是“真正的缺陷”,这些缺陷可能会在实际环境中出现。BugDetective 暴露了通常会逃避模式匹配静态分析和单元测试的错误,但通过手动测试或审查却难以发现。
当 BugDetective 作为全面的回归测试套的一部分应用时,该测试套还包括模式匹配静态分析、单元测试、容器内测试(适用于 Java)、API 测试、模块测试等,它可以帮助开发团队:
- 快速、自信地修改现有代码:通过使团队能够快速构建回归安全网,立即暴露引入的缺陷,并确定代码修改是否破坏了现有功能——即使团队拥有一个没有或只有少量测试的大型现有代码库。
- 控制开发成本和进度:通过尽早暴露错误(此时修复它们最快、成本最低),并测试广泛的潜在用户路径以发现可能延迟发布或需要发布后补丁的难以发现的问题。
- 优化开发资源:通过自动审查大约 80% 的编码问题,使开发人员能够花更少的时间进行逐行检查和调试,而将更多时间用于设计、算法和实现。
- 利用最新技术的强大功能,同时控制其风险:通过降低测试复杂企业应用程序(如 SOA/Web 服务和 Java EE 应用程序)的难度。
- 即时了解 Java 代码的质量和就绪情况:通过提供按需的客观代码评估并跟踪质量和进度目标。
Parasoft Corporation
在过去的 20 年里,Parasoft 一直在研究软件错误是如何以及为何会被引入应用程序中的。我们的解决方案利用了这些研究,在 SDLC 的整个过程中将质量作为持续的流程来交付。这有助于建立强大的代码基础、稳固的功能组件和健壮的业务流程。无论您是交付面向服务的架构(SOA)、维护遗留系统,还是改进质量流程——都可以借鉴我们的专业知识和屡获殊荣的产品,以提高生产力和业务应用程序的质量。有关更多信息,请访问 Parasoft 主页。