es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Recursión Infinita con Espías en las Pruebas Unitarias de Angular.

Nuevo en las pruebas unitarias aquí.

Tengo una situación en la que la función que estoy probando getFolderTree$() llama recursivamente a otra función getFolderChildren$(). Intenté configurar un espía para getFolderChildren$() como se ve en el intento de prueba unitaria a continuación. Sin embargo, esto resulta en que getFolderTree$() nunca tenga la oportunidad de llegar al caso base porque sigue obteniendo más y más hijos y se produce un error de tamaño de pila de llamadas máximas superado.

Cuando configuro el espía de getFolderChildren$() para devolver un array vacío, resuelvo el problema de la recursividad pero no puedo cubrir las líneas que tratan con los hijos.

¿Alguien sabe cómo puedo resolver este problema y aún obtener cobertura total de la función original? ¡Cualquier ayuda es apreciada!

Función Original

getFolderTree$(tenantId: number, folderId: number): Observable<foldertree> {
    return combineLatest([
      this.getFolder$(tenantId, folderId),
      this.getFolderChildren$(tenantId, folderId)]).pipe(
        map(([folder, subFolders]) => ({
          parent: { name: folder.folderName, id: folder.id, description: folder.description, children: [] } as FolderTree,
          childFolders: subFolders
        })),
        mergeMap(data => forkJoin([
          of(data.parent),
          ...data.childFolders.map(child => this.getFolderTree$(child.tenantId, child.id))
        ])),
        map(([parent, ...children]) => { parent.children = children.sort(this.sortByFolderName); return parent; })
      );
  }

Prueba Unitaria

“`
it('should get folder tree', () => {
let folder = {id: 1, tenantId: tenantID, folderName: 'some folder'} as IFolder;
let subFolders = [{id: 2, tenantId: tenantID, folderName: 'some child folder'} as IFolder];

<pre><code>spyOn(folderService, 'getFolder$').and.returnValue(of(folder));
spyOn(folderService, 'getFolderChildren$').and.returnValue(of(subFolders));

let result = folderService.getFolderTree$(tenantID, folderID);
result.subscribe(value => {
//expectation here
});
</code></pre>

});
“`

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    En este escenario, el problema es que cuando se llama a getFolderTree$(), sigue llamando de forma recursiva a getFolderChildren$(), lo que lleva a un error de desbordamiento de la pila de llamadas máxima. Configurar un espía para getFolderChildren$() y devolver un arreglo vacío puede solucionar el problema de recursión, pero significa que las líneas que manejan los hijos no se pueden cubrir.

    Una solución a este problema es usar el método jasmine.createSpyObj para crear un objeto espía para getFolderChildren$() y establecer manualmente el valor de retorno para cada llamada. Esto se puede hacer de la siguiente manera:

    it('should get folder tree', () => {
    
        const folder = {id: 1, tenantId: tenantID, folderName: 'some folder'} as IFolder;
        const subFolders = [{id: 2, tenantId: tenantID, folderName: 'some child folder'} as IFolder];
    
        // crear un objeto espía para folderService
        const folderServiceSpy = jasmine.createSpyObj('FolderService', ['getFolder$', 'getFolderChildren$']);
    
        // establecer el valor de retorno para la primera llamada a getFolder$
        folderServiceSpy.getFolder$.withArgs(tenantID, folderID).and.returnValue(of(folder));
    
        // crear un objeto espía para la segunda llamada a getFolderChildren$
        const getFolderChildrenSpy = jasmine.createSpyObj('getFolderChildren$', ['pipe']);
    
        // establecer el valor de retorno para la primera llamada a getFolderChildren$
        getFolderChildrenSpy.pipe.withArgs(
          switchMap(data => forkJoin([
            of(data),
            folderServiceSpy.getFolderChildren$.and.returnValue(of(subFolders))
          ])),
          map(data => ({ parent: data[0], childFolders: data[1] })),
          switchMap(data => forkJoin([
            of(data.parent),
            ...data.childFolders.map(child => folderServiceSpy.getFolderTree$(child.tenantId, child.id))
          ])),
          map(([parent, ...children]) => { parent.children = children.sort(this.sortByFolderName); return parent; })
        ).and.returnValues(
          of(1),
          of(2),
          of(3),
          of(4)
        );
    
        // establecer el objeto espía para la segunda llamada a getFolderChildren$
        folderServiceSpy.getFolderChildren$.and.returnValue(getFolderChildrenSpy);
    
        // llamar al método a probar
        const result = folderServiceSpy.getFolderTree$(tenantID, folderID);
    
        // agregar las expectativas
        result.subscribe(value => {
            // expectativa aquí
        });
    });
    

    Usar jasmine.createSpyObj te permite establecer manualmente el valor de retorno para cada llamada a getFolderChildren$(), lo que eliminará el problema de recursión al tiempo que te permitirá cubrir las líneas que manejan a los hijos.

Comments are closed.