### Question:
StepAnalyzer extends BaseKettleMetaverseComponent implements
  IClonableStepAnalyzer<T>, IFieldLineageMetadataProvider<T> { protected StepNodes processOutputs( T meta ) { StepNodes outputs = new StepNodes(); Map<String, RowMetaInterface> outputRowMetaInterfaces = getOutputRowMetaInterfaces( meta ); if ( MapUtils.isNotEmpty( outputRowMetaInterfaces ) ) { for ( Map.Entry<String, RowMetaInterface> entry : outputRowMetaInterfaces.entrySet() ) { String nextStepName = entry.getKey(); RowMetaInterface outputFields = entry.getValue(); if ( outputFields != null ) { for ( ValueMetaInterface valueMetaInterface : outputFields.getValueMetaList() ) { IMetaverseNode fieldNode = createOutputFieldNode( getDescriptor().getContext(), valueMetaInterface, nextStepName, getOutputNodeType() ); getMetaverseBuilder().addLink( rootNode, DictionaryConst.LINK_OUTPUTS, fieldNode ); outputs.addNode( nextStepName, valueMetaInterface.getName(), fieldNode ); } } else { LOGGER.warn( "No output fields found for step " + getStepName() ); } } } return outputs; }  @Override IMetaverseNode analyze( IComponentDescriptor descriptor, T meta ); @Override void postAnalyze( T meta ); Set<String> getInputStepNames( final T meta, final String fieldName ); String getStepName(); StepNodes getInputs(); StepNodes getOutputs(); void setDescriptor( IComponentDescriptor descriptor ); IComponentDescriptor getDescriptor(); Set<StepField> createStepFields( String fieldName, StepNodes stepNodes ); void validateState( IComponentDescriptor descriptor, T object ); IConnectionAnalyzer getConnectionAnalyzer(); void setConnectionAnalyzer( IConnectionAnalyzer connectionAnalyzer ); Map<String, RowMetaInterface> getInputFields( final TransMeta parentTransMeta,
                                                       final StepMeta parentStepMeta ); @Override Map<String, RowMetaInterface> getInputFields( T meta ); @Override RowMetaInterface getOutputFields( T meta ); @Override Set<IFieldMapping> getFieldMappings( T meta ); @Override Set<ComponentDerivationRecord> getChangeRecords( T meta ); void loadInputAndOutputStreamFields( T meta ); @Override final IClonableStepAnalyzer cloneAnalyzer(); IMetaverseNode getNode( final String name, final String type, final INamespace namespace,
                                 final String nodeKey, final Map<String, IMetaverseNode> nodeMap ); @Override void setDocumentAnalyzer( final IClonableDocumentAnalyzer documentAnalyzer ); @Override IClonableDocumentAnalyzer getDocumentAnalyzer(); @Override void setDocumentDescriptor( final IComponentDescriptor documentDescriptor ); @Override IComponentDescriptor getDocumentDescriptor(); @Override void setDocumentPath( final String documentPath ); static final String NONE; }### Answer:
@Test public void testProcessOutputs() throws Exception { Map<String, RowMetaInterface> outputRmis = new HashMap<>(); RowMetaInterface rowMetaInterface = mock( RowMetaInterface.class ); outputRmis.put( "nextStep", rowMetaInterface ); List<ValueMetaInterface> vmis = new ArrayList<>(); vmis.add( new ValueMeta( "full name" ) ); vmis.add( new ValueMeta( "address" ) ); vmis.add( new ValueMeta( "email" ) ); vmis.add( new ValueMeta( "date of birth" ) ); vmis.add( new ValueMeta( "ID" ) ); vmis.add( new ValueMeta( "occupation" ) ); doReturn( outputRmis ).when( analyzer ).getOutputRowMetaInterfaces( baseStepMeta ); when( rowMetaInterface.getValueMetaList() ).thenReturn( vmis ); doReturn( fieldNode ).when( analyzer ).createOutputFieldNode( any( IAnalysisContext.class ), any( ValueMetaInterface.class ), eq( "nextStep" ), eq( DictionaryConst.NODE_TYPE_TRANS_FIELD ) ); StepNodes stepNodes = analyzer.processOutputs( baseStepMeta ); assertEquals( 1, stepNodes.getStepNames().size() ); assertEquals( vmis.size(), stepNodes.getFieldNames().size() ); for ( ValueMetaInterface vmi : vmis ) { verify( analyzer ).createOutputFieldNode( any( IAnalysisContext.class ), eq( vmi ), eq( "nextStep" ), eq( DictionaryConst.NODE_TYPE_TRANS_FIELD ) ); } verify( builder, times( vmis.size() ) ).addLink( rootNode, DictionaryConst.LINK_OUTPUTS, fieldNode ); }