Esercitazione: Aggiungere unit test per progetti con oggetti visivi di Power BITutorial: Add unit tests for Power BI visual projects
Questo articolo contiene le nozioni di base per la scrittura di unit test per gli oggetti visivi di Power BI, include le procedure per:This article describes the basics of writing unit tests for your Power BI visuals, including how to:
- Configurare il framework di test dello strumento di esecuzione di test per JavaScript Karma, Jasmine.Set up the Karma JavaScript test runner testing framework, Jasmine.
- Usare il pacchetto powerbi-visuals-utils-testutils.Use the powerbi-visuals-utils-testutils package.
- Usare simulazioni per contribuire a semplificare gli unit test degli oggetti visivi di Power BI.Use mocks and fakes to help simplify unit testing of Power BI visuals.
PrerequisitiPrerequisites
- Un progetto con oggetti visivi di Power BI installatoAn installed Power BI visuals project
- Un ambiente Node.js configuratoA configured Node.js environment
Installare e configurare lo strumento di esecuzione di test per JavaScript Karma e JasmineInstall and configure the Karma JavaScript test runner and Jasmine
Aggiungere le librerie necessarie al file package.json nella sezione devDependencies
:Add the required libraries to the package.json file in the devDependencies
section:
"@babel/polyfill": "^7.2.5",
"@types/d3": "5.5.0",
"@types/jasmine": "2.5.37",
"@types/jasmine-jquery": "1.5.28",
"@types/jquery": "2.0.41",
"@types/karma": "3.0.0",
"@types/lodash-es": "4.17.1",
"coveralls": "3.0.2",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine": "2.5.2",
"jasmine-core": "2.5.2",
"jasmine-jquery": "2.1.1",
"jquery": "3.1.1",
"karma": "3.1.1",
"karma-chrome-launcher": "2.2.0",
"karma-coverage": "1.1.2",
"karma-coverage-istanbul-reporter": "^2.0.4",
"karma-jasmine": "2.0.1",
"karma-junit-reporter": "^1.2.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-typescript": "^3.0.13",
"karma-typescript-preprocessor": "0.4.0",
"karma-webpack": "3.0.5",
"puppeteer": "1.17.0",
"style-loader": "0.23.1",
"ts-loader": "5.3.0",
"ts-node": "7.0.1",
"tslint": "^5.12.0",
"webpack": "4.26.0"
Per altre informazioni su package.json, vedere la descrizione in npm-package.json.To learn more about package.json, see the description at npm-package.json.
Salvare il file package.json ed eseguire il comando seguente nella posizione package.json
:Save the package.json file and, at the package.json
location, run the following command:
npm install
Lo strumento di gestione pacchetti installa tutti i nuovi pacchetti aggiunti a package.json.The package manager installs all new packages that are added to package.json.
Per eseguire gli unit test, configurare lo strumento di esecuzione di test e la configurazione di webpack
.To run unit tests, configure the test runner and webpack
config.
Il codice seguente è un esempio del file test.webpack.config.js:The following code is a sample of the test.webpack.config.js file:
const path = require('path');
const webpack = require("webpack");
module.exports = {
devtool: 'source-map',
mode: 'development',
optimization : {
concatenateModules: false,
minimize: false
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.tsx?$/i,
enforce: 'post',
include: /(src)/,
exclude: /(node_modules|resources\/js\/vendor)/,
loader: 'istanbul-instrumenter-loader',
options: { esModules: true }
},
{
test: /\.less$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'less-loader',
options: {
paths: [path.resolve(__dirname, 'node_modules')]
}
}
]
}
]
},
externals: {
"powerbi-visuals-api": '{}'
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.css']
},
output: {
path: path.resolve(__dirname, ".tmp/test")
},
plugins: [
new webpack.ProvidePlugin({
'powerbi-visuals-api': null
})
]
};
Il codice seguente è un esempio del file karma.conf.ts:The following code is a sample of the karma.conf.ts file:
"use strict";
const webpackConfig = require("./test.webpack.config.js");
const tsconfig = require("./test.tsconfig.json");
const path = require("path");
const testRecursivePath = "test/visualTest.ts";
const srcOriginalRecursivePath = "src/**/*.ts";
const coverageFolder = "coverage";
process.env.CHROME_BIN = require("puppeteer").executablePath();
import { Config, ConfigOptions } from "karma";
module.exports = (config: Config) => {
config.set(<ConfigOptions>{
mode: "development",
browserNoActivityTimeout: 100000,
browsers: ["ChromeHeadless"], // or Chrome to use locally installed Chrome browser
colors: true,
frameworks: ["jasmine"],
reporters: [
"progress",
"junit",
"coverage-istanbul"
],
junitReporter: {
outputDir: path.join(__dirname, coverageFolder),
outputFile: "TESTS-report.xml",
useBrowserName: false
},
singleRun: true,
plugins: [
"karma-coverage",
"karma-typescript",
"karma-webpack",
"karma-jasmine",
"karma-sourcemap-loader",
"karma-chrome-launcher",
"karma-junit-reporter",
"karma-coverage-istanbul-reporter"
],
files: [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/jasmine-jquery/lib/jasmine-jquery.js",
{
pattern: './capabilities.json',
watched: false,
served: true,
included: false
},
testRecursivePath,
{
pattern: srcOriginalRecursivePath,
included: false,
served: true
}
],
preprocessors: {
[testRecursivePath]: ["webpack", "coverage"]
},
typescriptPreprocessor: {
options: tsconfig.compilerOptions
},
coverageIstanbulReporter: {
reports: ["html", "lcovonly", "text-summary", "cobertura"],
dir: path.join(__dirname, coverageFolder),
'report-config': {
html: {
subdir: 'html-report'
}
},
combineBrowserReports: true,
fixWebpackSourcePaths: true,
verbose: false
},
coverageReporter: {
dir: path.join(__dirname, coverageFolder),
reporters: [
// reporters not supporting the `file` property
{ type: 'html', subdir: 'html-report' },
{ type: 'lcov', subdir: 'lcov' },
// reporters supporting the `file` property, use `subdir` to directly
// output them in the `dir` directory
{ type: 'cobertura', subdir: '.', file: 'cobertura-coverage.xml' },
{ type: 'lcovonly', subdir: '.', file: 'report-lcovonly.txt' },
{ type: 'text-summary', subdir: '.', file: 'text-summary.txt' },
]
},
mime: {
"text/x-typescript": ["ts", "tsx"]
},
webpack: webpackConfig,
webpackMiddleware: {
stats: "errors-only"
}
});
};
Se necessario, è possibile modificare questa configurazione.If necessary, you can modify this configuration.
Il codice in karma.conf.js contiene la variabile seguente:The code in karma.conf.js contains the following variable:
recursivePathToTests
: individua il codice del testrecursivePathToTests
: Locates the test codesrcRecursivePath
: individua il codice JavaScript di output dopo la compilazionesrcRecursivePath
: Locates the output JavaScript code after compilingsrcCssRecursivePath
: individua i CSS di output dopo la compilazione di un numero inferiore di file con stilisrcCssRecursivePath
: Locates the output CSS after compiling less file with stylessrcOriginalRecursivePath
: individua il codice sorgente dell'oggetto visivosrcOriginalRecursivePath
: Locates the source code of your visualcoverageFolder
: determina la posizione in cui deve essere creato il report di code coveragecoverageFolder
: Determines where the coverage report is to be created
Il file di configurazione include le proprietà seguenti:The configuration file includes the following properties:
singleRun: true
: i test vengono eseguiti in un sistema di integrazione continua oppure possono essere eseguiti una sola volta.singleRun: true
: Tests are run on a continuous integration (CI) system, or they can be run one time. È possibile modificare l'impostazione in false per il debug dei test.You can change the setting to false for debugging your tests. Karma mantiene il browser in esecuzione in modo che sia possibile usare la console per il debug.Karma keeps the browser running so that you can use the console for debugging.files: [...]
: in questa matrice è possibile specificare i file da caricare nel browser.files: [...]
: In this array, you can specify the files to load to the browser. In genere, si tratta di file di origine, test case e librerie (Jasmine, utilità di test).Usually, there are source files, test cases, libraries (Jasmine, test utilities). È possibile aggiungere altri file all'elenco, se necessario.You can add additional files to the list, as necessary.preprocessors
: in questa sezione vengono configurate le azioni che vengono eseguite prima degli unit test.preprocessors
: In this section, you configure actions that run before the unit tests run. Precompilano il codice TypeScript in JavaScript, preparano i file di mappa di origine e generano il report della code coverage.They precompile the typescript to JavaScript, prepare source map files, and generate code coverage report. È possibile disabilitarecoverage
quando si esegue il debug dei test.You can disablecoverage
when you debug your tests. La code coverage genera codice aggiuntivo per il codice di controllo per la code coverage dei test, che complica i test di debug.Coverage generates additional code for check code for the test coverage, which complicates debugging tests.
Per le descrizioni di tutte le configurazioni di Karma, passare alla pagina Karma Configuration File (File di configurazione di Karma).For descriptions of all Karma configurations, go to the Karma Configuration File page.
Per praticità, è possibile aggiungere un comando test in scripts
:For your convenience, you can add a test command into scripts
:
{
"scripts": {
"pbiviz": "pbiviz",
"start": "pbiviz start",
"typings":"node node_modules/typings/dist/bin.js i",
"lint": "tslint -r \"node_modules/tslint-microsoft-contrib\" \"+(src|test)/**/*.ts\"",
"pretest": "pbiviz package --resources --no-minify --no-pbiviz --no-plugin",
"test": "karma start"
}
...
}
È ora possibile iniziare la scrittura degli unit test.You're now ready to begin writing your unit tests.
Controllare l'elemento DOM dell'oggetto visivoCheck the DOM element of the visual
Per testare l'oggetto visivo, creare prima di tutto un'istanza dell'oggetto visivo stesso.To test the visual, first create an instance of visual.
Creare un generatore dell'istanza dell'oggetto visivoCreate a visual instance builder
Aggiungere un file visualBuilder.ts alla cartella test usando il codice seguente:Add a visualBuilder.ts file to the test folder by using the following code:
import {
VisualBuilderBase
} from "powerbi-visuals-utils-testutils";
import {
BarChart as VisualClass
} from "../src/visual";
import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
export class BarChartBuilder extends VisualBuilderBase<VisualClass> {
constructor(width: number, height: number) {
super(width, height);
}
protected build(options: VisualConstructorOptions) {
return new VisualClass(options);
}
public get mainElement() {
return this.element.children("svg.barChart");
}
}
È disponibile un metodo build
per la creazione di un'istanza dell'oggetto visivo.There's build
method for creating an instance of your visual. mainElement
è un metodo Get che restituisce un'istanza dell'elemento DOM (Document Object Model) "radice" nell'oggetto visivo.mainElement
is a get method, which returns an instance of "root" document object model (DOM) element in your visual. Il metodo Get è facoltativo, ma semplifica la scrittura dello unit test.The getter is optional, but it makes writing the unit test easier.
A questo punto è disponibile una build di un'istanza dell'oggetto visivo.You now have a build of an instance of your visual. Verrà ora scritto il test case.Let's write the test case. Il test case controlla gli elementi SVG creati quando viene visualizzato l'oggetto visivo.The test case checks the SVG elements that are created when your visual is displayed.
Creare un file TypeScript per la scrittura di test caseCreate a typescript file to write test cases
Aggiungere un file visualTest.ts per i test case usando il codice seguente:Add a visualTest.ts file for the test cases by using the following code:
import powerbi from "powerbi-visuals-api";
import { BarChartBuilder } from "./VisualBuilder";
import {
BarChart as VisualClass
} from "../src/visual";
import VisualBuilder = powerbi.extensibility.visual.test.BarChartBuilder;
describe("BarChart", () => {
let visualBuilder: VisualBuilder;
let dataView: DataView;
beforeEach(() => {
visualBuilder = new VisualBuilder(500, 500);
});
it("root DOM element is created", () => {
expect(visualBuilder.mainElement).toBeInDOM();
});
});
Vengono chiamati diversi metodi:Several methods are called:
describe
: descrive un test case.describe
: Describes a test case. Nell'ambito del framework Jasmine, spesso descrive una suite o un gruppo di specifiche.In the context of the Jasmine framework, it often describes a suite or group of specs.beforeEach
: viene chiamato prima di ogni chiamata del metodoit
, definito nel metododescribe
.beforeEach
: Is called before each call of theit
method, which is defined in thedescribe
method.it
: definisce una singola specifica. Il metodoit
deve contenere uno o più oggettiexpectations
.it
: Defines a single spec. Theit
method should contain one or moreexpectations
.expect
: crea una previsione per una specifica. Una specifica ha esito positivo se tutte le previsioni vengono passate senza errori.expect
: Creates an expectation for a spec. A spec succeeds if all expectations pass without any failures.toBeInDOM
: uno dei metodi di matchers.toBeInDOM
: One of the matchers methods. Per altre informazioni su matchers, vedere Jasmine Namespace: matchers (Spazio dei nomi di Jasmine: matchers).For more information about matchers, see Jasmine Namespace: matchers.
Per altre informazioni su Jasmine, vedere la pagina della documentazione del framework Jasmine.For more information about Jasmine, see the Jasmine framework documentation page.
Avviare gli unit testLaunch unit tests
Questo test verifica che venga creato l'elemento SVG radice degli oggetti visivi.This test checks that root SVG element of the visuals is created. Per eseguire lo unit test, immettere il comando seguente nello strumento da riga di comando:To run the unit test, enter the following command in the command-line tool:
npm run test
karma.js
esegue il test case nel browser Chrome.karma.js
runs the test case in the Chrome browser.
Nota
È necessario installare Google Chrome in locale.You must install Google Chrome locally.
Nella finestra della riga di comando si ottiene l'output seguente:In the command-line window, you'll get following output:
> karma start
23 05 2017 12:24:26.842:WARN [watcher]: Pattern "E:/WORKSPACE/PowerBI/PowerBI-visuals-sampleBarChart/data/*.csv" does not match any file.
23 05 2017 12:24:30.836:WARN [karma]: No captured browser, open https://localhost:9876/
23 05 2017 12:24:30.849:INFO [karma]: Karma v1.3.0 server started at https://localhost:9876/
23 05 2017 12:24:30.850:INFO [launcher]: Launching browser Chrome with unlimited concurrency
23 05 2017 12:24:31.059:INFO [launcher]: Starting browser Chrome
23 05 2017 12:24:33.160:INFO [Chrome 58.0.3029 (Windows 10 0.0.0)]: Connected on socket /#2meR6hjXFmsE_fjiAAAA with id 5875251
Chrome 58.0.3029 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.194 secs / 0.011 secs)
=============================== Coverage summary ===============================
Statements : 27.43% ( 65/237 )
Branches : 19.84% ( 25/126 )
Functions : 43.86% ( 25/57 )
Lines : 20.85% ( 44/211 )
================================================================================
Come aggiungere dati statici per gli unit testHow to add static data for unit tests
Creare il file visualData.ts nella cartella test usando il codice seguente:Create the visualData.ts file in the test folder by using the following code:
import powerbi from "powerbi-visuals-api";
import DataView = powerbi.DataView;
import {
testDataViewBuilder,
getRandomNumbers
} from "powerbi-visuals-utils-testutils";
export class SampleBarChartDataBuilder extends TestDataViewBuilder {
public static CategoryColumn: string = "category";
public static MeasureColumn: string = "measure";
public constructor() {
super();
...
}
public getDataView(columnNames?: string[]): DataView {
let dateView: any = this.createCategoricalDataViewBuilder([
...
],
[
...
], columnNames).build();
// there's client side computed maxValue
let maxLocal = 0;
this.valuesMeasure.forEach((item) => {
if (item > maxLocal) {
maxLocal = item;
}
});
(<any>dataView).categorical.values[0].maxLocal = maxLocal;
}
}
La classe SampleBarChartDataBuilder
estende TestDataViewBuilder
e implementa il metodo astratto getDataView
.The SampleBarChartDataBuilder
class extends TestDataViewBuilder
and implements the abstract method getDataView
.
Quando si inseriscono i dati in bucket di campi dati, Power BI produce un oggetto dataview
categorico basato sui dati.When you put data into data-field buckets, Power BI produces a categorical dataview
object that's based on your data.
Negli unit test non sono disponibili funzioni di base di Power BI per riprodurre i dati.In unit tests, you don't have Power BI core functions to reproduce the data. Tuttavia, è necessario eseguire il mapping dei dati statici all'oggetto dataview
categorico.But you need to map your static data to the categorical dataview
. La classe TestDataViewBuilder
consente di eseguirne il mapping.The TestDataViewBuilder
class can help you map it.
Per altre informazioni sul mapping di viste dati, vedere DataViewMappings.For more information about Data View mapping, see DataViewMappings.
Nel metodo getDataView
si chiama il metodo createCategoricalDataViewBuilder
con i dati.In the getDataView
method, you call the createCategoricalDataViewBuilder
method with your data.
Il file capabilities.json per l'oggetto visivo sampleBarChart
include gli oggetti dataRoles and dataViewMapping:In sampleBarChart
visual capabilities.json file, we have dataRoles and dataViewMapping objects:
"dataRoles": [
{
"displayName": "Category Data",
"name": "category",
"kind": "Grouping"
},
{
"displayName": "Measure Data",
"name": "measure",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"conditions": [
{
"category": {
"max": 1
},
"measure": {
"max": 1
}
}
],
"categorical": {
"categories": {
"for": {
"in": "category"
}
},
"values": {
"select": [
{
"bind": {
"to": "measure"
}
}
]
}
}
}
],
Per generare lo stesso mapping, è necessario impostare i parametri seguenti sul metodo createCategoricalDataViewBuilder
:To generate the same mapping, you must set the following params to createCategoricalDataViewBuilder
method:
([
{
source: {
displayName: "Category",
queryName: SampleBarChartData.ColumnCategory,
type: ValueType.fromDescriptor({ text: true }),
roles: {
Category: true
},
},
values: this.valuesCategory
}
],
[
{
source: {
displayName: "Measure",
isMeasure: true,
queryName: SampleBarChartData.MeasureColumn,
type: ValueType.fromDescriptor({ numeric: true }),
roles: {
Measure: true
},
},
values: this.valuesMeasure
},
], columnNames)
Dove this.valuesCategory
è una matrice di categorie:Where this.valuesCategory
is an array of categories:
public valuesCategory: string[] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
Mentre this.valuesMeasure
è una matrice di misure per ogni categoria:And this.valuesMeasure
is an array of measures for each category:
public valuesMeasure: number[] = [742731.43, 162066.43, 283085.78, 300263.49, 376074.57, 814724.34, 570921.34];
È ora possibile usare la classe SampleBarChartDataBuilder
nello unit test.Now, you can use the SampleBarChartDataBuilder
class in your unit test.
La classe ValueType
è definita nel pacchetto powerbi-visuals-utils-testutilsThe ValueType
class is defined in the powerbi-visuals-utils-testutils package. e il metodo createCategoricalDataViewBuilder
richiede la libreria lodash
.And the createCategoricalDataViewBuilder
method requires the lodash
library.
Aggiungere questi pacchetti alle dipendenze.Add these packages to the dependencies.
In package.json
nella sezione devDependencies
In package.json
at devDependencies
section
"lodash-es": "4.17.1",
"powerbi-visuals-utils-testutils": "2.2.0"
ChiamataCall
npm install
Per installare la libreria lodash-es
.to install lodash-es
library.
È ora possibile eseguire di nuovo lo unit test.Now, you can run the unit test again. È necessario ottenere l'output seguente:You must get the following output:
> karma start
23 05 2017 16:19:54.318:WARN [watcher]: Pattern "E:/WORKSPACE/PowerBI/PowerBI-visuals-sampleBarChart/data/*.csv" does not match any file.
23 05 2017 16:19:58.333:WARN [karma]: No captured browser, open https://localhost:9876/
23 05 2017 16:19:58.346:INFO [karma]: Karma v1.3.0 server started at https://localhost:9876/
23 05 2017 16:19:58.346:INFO [launcher]: Launching browser Chrome with unlimited concurrency
23 05 2017 16:19:58.394:INFO [launcher]: Starting browser Chrome
23 05 2017 16:19:59.873:INFO [Chrome 58.0.3029 (Windows 10 0.0.0)]: Connected on socket /#NcNTAGH9hWfGMCuEAAAA with id 3551106
Chrome 58.0.3029 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (1.266 secs / 1.052 secs)
=============================== Coverage summary ===============================
Statements : 56.72% ( 135/238 )
Branches : 32.54% ( 41/126 )
Functions : 66.67% ( 38/57 )
Lines : 52.83% ( 112/212 )
================================================================================
L'oggetto visivo verrà aperto nel browser Chrome, come illustrato:Your visual opens in the Chrome browser, as shown:
Il riepilogo mostra che la copertura è aumentata.The summary shows that coverage has increased. Per altre informazioni sulla code coverage corrente, aprire coverage\index.html
.To learn more about current code coverage, open coverage\index.html
.
In alternativa, esaminare l'ambito della cartella src
:Or look at the scope of the src
folder:
Nell'ambito del file è possibile visualizzare il codice sorgente.In the scope of file, you can view the source code. Le utilità Coverage
evidenzieranno la riga in rosso se un determinato codice non viene eseguito durante gli unit test.The Coverage
utilities would highlight the row in red if certain code isn't executed during the unit tests.
Importante
Il valore della code coverage non significa che la code coverage della funzionalità sia appropriata per l'oggetto visivo.Code coverage doesn't mean that you have good functionality coverage of the visual. Un semplice unit test fornisce il 96% di code coverage in src\visual.ts
.One simple unit test provides over 96 percent coverage in src\visual.ts
.
Passaggi successiviNext steps
Quando l'oggetto visivo è pronto, è possibile inviarlo per la pubblicazione.When your visual is ready, you can submit it for publication. Per altre informazioni, vedere Pubblicare oggetti visivi di Power BI in AppSource.For more information, see Publish Power BI visuals to AppSource.