A static, language-independent code analysis tool that generates test coverage metrics based on input generated from other external tools.
In order to generate the coverage metric, grab the latest release of the tool from here, unzip the archive, navigate to the place where you extracted the contents in a terminal and run the following (you'll at least need Java 1.8 to run):
$ java -jar ./spektrum.jar [language] [input]
Where language
is the language of the project (at the moment only java
and cs
are supported - for Java
and C#) and input
is the path to the input file.
In case you only want to try it out, there is a couple of sample input files in the ./sample-inputs
directory.
Here are some examples of how you'd run the tool with the sample inputs:
$ java -jar ./spektrum.jar cs ./sample-inputs/honeydew_cs.json # for C#
$ java -jar ./spektrum.jar java ./sample-inputs/insider_java.json # for Java
After running, the tool will generate a model.json
file containing information about the model's coverage in
the ./analytics
directory. This file will contain a list of objects that have the following fields:
Field | Type | Short Description |
---|---|---|
identifier | String | The unique identifier of the object |
type | String | The type of the object |
coverage | Float | The test coverage % of the object (between 0.0 and 1.0) |
testAmount | Float | The % of how much of the children are test units (between 0.0 and 1.0) |
children | List | A recursive list that contains the children on the object |
The identifiers of the objects respect the following notation: [parent_identifier]->[object_identifier]
. So if
you'd have a class Foo
that has a bar()
method in it, the identifier of the object that corresponds to the
method would be Foo->bar()
.
The available types differ from one language to another. Here are the type hierarchies used for the currently supported languages:
- C#:
PROJECT
>FILE
>NAMESPACE
>CLASS
>METHOD
- Java:
PROJECT
>PACKAGE
>CLASS
>METHOD
In case you want to see the output of the tool in a more human-readable way, you can use the visualizer tool, that you
can access by opening ./visualizer/index.html
in a browser.
After opening it, use the file picker to select the file that was generated by the tool and after that you'll be able to see your project's hierarchy in a tree view where you can search for certain entries and filter by the coverage and test amount percentage.
A rule is a function that takes in one parameter that contains information about a unit and returns a
boolean: true
if the unit should be considered a test unit and false
if the unit should be considered
a testable unit.
The ./rules
directory contains one subdirectory for each language that is supported by the tool. Each one of those
subdirectories contains a rule.groovy
file that has a check(unitInfo)
function inside it. This function
contains the logic that is used to determine whether a unit is a test unit or a testable unit.
If you feel like the default rules of this tool don't work well with your project, you have the option to write your own
custom rules to identify which units should be considered test units. All you have to do to accomplish that is you have
to replace the default logic from the check
function with your own logic. That's it!
Let's say you don't like the rule used for Java projects. All you'd have to do is you have to do
to ./rules/java/rule.groovy
's check
function and replace its content with whatever you feel fits your
project (more info about the unitInfo
parameter will come in the next subsection).
package rules.java
def coolRuleA(unitInfo) {
def isRespected = false
// rule A logic...
return isRespected
}
def coolRuleB(unitInfo) {
def isRespected = false
// rule B logic...
return isRespected
}
def check(unitInfo) {
return coolRuleA(unitInfo) || coolRuleB(unitInfo)
}
The unitInfo
parameter contains all the information that is available about a certain unit. This information
differs from one language to the other:
- C#
Field | Type | Description |
---|---|---|
unitInfo.project.name | String | Name of the project in which the unit is |
unitInfo.project.path | String | Path to the project in which the unit is |
unitInfo.project.projectReferences | Set<String> | References to the project in which the unit is |
unitInfo.project.externalReferences | Set<String> | References to other projects made by the project in which the unit is |
unitInfo.file.name | String | Name of the file of the unit |
unitInfo.file.path | String | Path to the file of the unit |
unitInfo.namespace.name | String | Name of the unit's namespace |
unitInfo.cls.name | String | Name if the unit's class |
unitInfo.cls.type | String | Type of the unit's class |
unitInfo.cls.usingStatements | Set | Using statements of the unit's class |
unitInfo.cls.attributes | Set | Attributes of the unit's class |
unitInfo.cls.usedClasses | Set | Classes used by unit's class |
unitInfo.method.name | String | Name of the unit (format is <file>-><namespace>.<class>@<method>#<params> ) |
unitInfo.method.attributes | Set<String> | Attributes of the unit |
unitInfo.method.modifiers | Set<String> | Modifiers of the unit |
unitInfo.method.callers | Set<String> | Methods that call the unit (in the format from the TheOutput section) |
unitInfo.method.calledMethods | Set<String> | Methods called by the unit (in the format from the TheOutput section) |
unitInfo.method.type | String | Type of the unit |
- Java
Field | Type | Description |
---|---|---|
unitInfo.project.name | String | Name of unit's project |
unitInfo.pkg.name | String | Name of unit's package |
unitInfo.cls.name | String | Name of unit's class |
unitInfo.cls.dependencies | Set | Dependencies used in unit's class |
unitInfo.method.signature | String | Unit's signature |
unitInfo.method.callers | Set | Methods that call the unit |
unitInfo.method.calledMethods | Set | Methods called by the unit |