Stubbing Logger classes avec des méthodes acceptant les exceptions
J'ai récemment eu besoin d'écrire un test qui vérifie si une exception est enregistrée. Nous avons un enregistreur mais il est construit avec des méthodes statiques, il ne peut donc pas être stubé. Mais je ne voulais pas tester la logique du Logger, j'ai donc décidé de la réécrire pour qu'elle soit instanciable.
Une fois le refactoring terminé, j'ai essayé de me moquer de cela avec ApexMocks. Une surprise attendue - StubAPI ne peut pas se moquer des classes avec des méthodes qui acceptent les exceptions comme argument ( logException(Exception ex)par exemple).
L'erreur générée est System.TypeException: @Override specified for non-overriding method: void Logger__sfdc_ApexStub.logException(java.lang.Exception ex)
Exemple de code:
Logger.cls
public class Logger {
public void logEception(Exception ex) {
// logging code
}
}
Classe de test:
@isTest
private class Test_Logger {
@isTest
private static void testMockability() {
Logger mockLogger = (Logger) Test.createStub(Logger.class, new Stub());
}
private class Stub implements StubProvider {
public Object handleMethodCall(
Object stubbedObject,
String stubbedMethodName,
System.Type returnType,
List<System.Type> listOfParamTypes,
List<String> listOfParamNames,
List<Object> listOfArgs
) {
return null;
}
}
}
Réponses
La seule solution que j'ai trouvée était de rendre les méthodes défaillantes privées et de les exposer uniquement en tant que méthodes statiques. Donc, je me suis retrouvé avec une classe avec des méthodes statiques, qui utilise un singleton mockable sous le capot. Le problème restant est que les méthodes privées sont en fait appelées et non stubbées, j'ai donc ajouté une isMockedvariable pour empêcher l'exécution des méthodes privées.
L'exemple de code ci-dessous est simplifié pour ne laisser que ce qui est important. Dans le code de production, j'utilise ApexMocks lib, mais cela n'a aucun rapport avec le problème.
public class Logger {
@TestVisible
private static Boolean isMocked = false;
public static void logEception(Exception ex) {
new Logger().logException(ex);
}
private void logEception(Exception ex) {
if (isMocked) {
return;
}
// logging code
}
}
Tester
@isTest
private class Test_Logger {
@isTest
private static void testMockability() {
Logger.isMocked = true;
Logger mockLogger = (Logger) Test.createStub(Logger.class, new Stub());
}
private class Stub implements StubProvider {
public Object handleMethodCall(
Object stubbedObject,
String stubbedMethodName,
System.Type returnType,
List<System.Type> listOfParamTypes,
List<String> listOfParamNames,
List<Object> listOfArgs
) {
return null;
}
}
}