Регистрация  |  Вход

Тестирование отправки email из батча

Всем привет, заметил одну странность - есть класс:

public class MySample {
public static void sendEmail(){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTargetObjectId(UserInfo.getUserId());
mail.setTemplateId([SELECT Id FROM EmailTemplate LIMIT 1][0].Id);
mail.setSaveAsActivity(false);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}

и юнит тест

private static testMethod void testEmailSending() {
Test.startTest();
Integer emailInvocationsBefore = Limits.getEmailInvocations();

MySample.sendEmail();

System.assert(emailInvocationsBefore != Limits.getEmailInvocations(), 'Email did\'t send');
Test.stopTest();
}

Тест проходит успешно.

Теперь попробуем так, есть простой батч:

public class SampleBatch implements Database.Batchable<Object> {

public List<Object> start(Database.BatchableContext BC) {
return new List<String>{'test'};
}

public void execute(Database.BatchableContext BC, List<Object> scope) {
MySample.sendEmail();
}

public void finish(Database.BatchableContext BC) {
}
}

и тест к нему

private static testMethod void testEmailSendingFromBatch() {
Test.startTest();
Integer emailInvocationsBefore = Limits.getEmailInvocations();

Database.executeBatch(new SampleBatch());

Test.stopTest();

System.assert(emailInvocationsBefore != Limits.getEmailInvocations(), 'Email did\'t send');
}

Данный тест не проходит и в логах везде Number of Email Invocations: 0 out of 10.
В чём подвох?

PS
При большом желании можно протестировать и так:

private static testMethod void testEmailSendingFromBatch2() {
Test.startTest();
Integer emailInvocationsBefore = Limits.getEmailInvocations();

(new SampleBatch()).execute(null, null);

System.assert(emailInvocationsBefore != Limits.getEmailInvocations(), 'Email did\'t send');
Test.stopTest();
}

Но это не интересно :)

Всем привет, заметил одну странность - есть класс:

[code]
public class MySample {
    public static void sendEmail(){
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setTargetObjectId(UserInfo.getUserId());
        mail.setTemplateId([SELECT Id FROM EmailTemplate LIMIT 1][0].Id);
        mail.setSaveAsActivity(false);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
}
[/code]

и юнит тест

[code]
private static testMethod void testEmailSending() {
        Test.startTest();
            Integer emailInvocationsBefore = Limits.getEmailInvocations();
            
            MySample.sendEmail();
        
            System.assert(emailInvocationsBefore != Limits.getEmailInvocations(), 'Email did\'t send');
        Test.stopTest();
}
[/code]

Тест проходит успешно.

Теперь попробуем так, есть простой батч:

[code]
public class SampleBatch implements Database.Batchable<Object> {

	public List<Object> start(Database.BatchableContext BC) {
		return new List<String>{'test'};
	}

	public void execute(Database.BatchableContext BC, List<Object> scope) {
		MySample.sendEmail();
	}

	public void finish(Database.BatchableContext BC) {
	}
}
[/code]

и тест к нему

[code]
private static testMethod void testEmailSendingFromBatch() {
        Test.startTest();
            Integer emailInvocationsBefore = Limits.getEmailInvocations();
            
            Database.executeBatch(new SampleBatch());
        
        Test.stopTest();
        
        System.assert(emailInvocationsBefore != Limits.getEmailInvocations(), 'Email did\'t send');
}
[/code]

Данный тест не проходит и в логах везде Number of Email Invocations: 0 out of 10.
В чём подвох?

PS 
При большом желании  можно протестировать и так:
[code]
private static testMethod void testEmailSendingFromBatch2() {
        Test.startTest();
            Integer emailInvocationsBefore = Limits.getEmailInvocations();
            
            (new SampleBatch()).execute(null, null);
        
            System.assert(emailInvocationsBefore != Limits.getEmailInvocations(), 'Email did\'t send');
        Test.stopTest();
}
[/code]
Но это не интересно :)

Дима Лисовский
Данный тест не проходит

А в чем ошибка?

[quote="Дима Лисовский"]Данный тест не проходит[/quote]
А в чем ошибка?

assert

assert

execute точно отрабатывает?
И с какого счастья отработанный батч должен повлиять на контекст вне его выполнения?

Не уверен, что поможет, но может сделать ассерт ДО Test.stopTest();.

execute точно отрабатывает?
И с какого счастья отработанный батч должен повлиять на контекст вне его выполнения?

Не уверен, что поможет, но может сделать ассерт ДО Test.stopTest();.

RasMisha
execute точно отрабатывает?

execute отрабатывает, в логе есть вызов метода отправки email, но это никак не отражается на лимитах

RasMisha
Не уверен, что поможет, но может сделать ассерт ДО Test.stopTest();.

нет, все асинхронные операции начинают выполняться после Test.stopTest()

[quote="RasMisha"]execute точно отрабатывает?[/quote]
execute отрабатывает, в логе есть вызов метода отправки email, но это никак не отражается на лимитах

[quote="RasMisha"]Не уверен, что поможет, но может сделать ассерт ДО Test.stopTest();.[/quote]
нет, все асинхронные операции начинают выполняться после Test.stopTest()



Ну а контекстов то получается все равно несколько, и ты смотришь лимиты в двух разных.

Ну а контекстов то получается все равно несколько, и ты смотришь лимиты в двух разных.

Ну так смотри, логика примерно такая:
1) Ты запускаешь отправку емейлов в контексте батча
2) Проверяешь отправлен ли хотя бы один email НЕ(!) в контексте батча.

Даже если бы этот тест прошел, он бы не имел никакого смысла, кроме как запихать assert в тест.

Дима Лисовский
нет, все асинхронные операции начинают выполняться после Test.stopTest()

Особенно это заметно в первом тесте.

Ну так смотри, логика примерно такая:
1) Ты запускаешь отправку емейлов в контексте батча
2) Проверяешь отправлен ли хотя бы один email НЕ(!) в контексте батча.

Даже если бы этот тест прошел, он бы не имел никакого смысла, кроме как запихать assert в тест.

[quote="Дима Лисовский"]нет, все асинхронные операции начинают выполняться после Test.stopTest()[/quote]
Особенно это заметно в первом тесте.

Gres
Ну а контекстов то получается все равно несколько, и ты смотришь лимиты в двух разных.

Я это понимаю, теперь вопрос, как протестить отправился email или нет? И почему во всём логе везде Number of Email Invocations: 0 out of 10 (включая лог батча)

RasMisha
Особенно это заметно в первом тесте.

а что не так с первым тестом, там ведь нет асинхронного кода

[quote="Gres"]Ну а контекстов то получается все равно несколько, и ты смотришь лимиты в двух разных.[/quote]

Я это понимаю, теперь вопрос, как протестить отправился email или нет? И почему во всём логе везде Number of Email Invocations: 0 out of 10 (включая лог батча)

[quote="RasMisha"]Особенно это заметно в первом тесте.[/quote]

а что не так с первым тестом, там ведь нет асинхронного кода

Дима Лисовский
Gres
Ну а контекстов то получается все равно несколько, и ты смотришь лимиты в двух разных.

Я это понимаю, теперь вопрос, как протестить отправился email или нет? И почему во всём логе везде Number of Email Invocations: 0 out of 10 (включая лог батча)


Потому что там где ты это проверяешь не отправленно ни одного письма.
По сути тебе просто надо проверить, что батч запустился (cronJobId поищи , но его точно между startTest() и stopTest(), или если что-то изменяется помимо отправки email).
Email отправляй из утилитарного класса и его уже тестируй.

а что не так с первым тестом, там ведь нет асинхронного кода

Ну ты просто так написал, что ассерт писать есть смысл только после Test.stopTest()

[quote="Дима Лисовский"][quote="Gres"]Ну а контекстов то получается все равно несколько, и ты смотришь лимиты в двух разных.[/quote]

Я это понимаю, теперь вопрос, как протестить отправился email или нет? И почему во всём логе везде Number of Email Invocations: 0 out of 10 (включая лог батча)[/quote]
Потому что там где ты это проверяешь не отправленно ни одного письма.
По сути тебе просто надо проверить, что батч запустился (cronJobId поищи , но его точно между startTest() и stopTest(), или если что-то изменяется помимо отправки email).
Email отправляй из утилитарного класса и его уже тестируй.

[quote]а что не так с первым тестом, там ведь нет асинхронного кода[/quote]
Ну ты просто так написал, что ассерт писать есть смысл только после Test.stopTest()

RasMisha
Потому что там где ты это проверяешь не отправленно ни одного письма.

так почему нет в логе?

[quote="RasMisha"]Потому что там где ты это проверяешь не отправленно ни одного письма. [/quote]
так почему нет в логе?

public void execute(Database.BatchableContext BC, List<Object> scope) {
System.debug(
LoggingLevel.ERROR,
'before Limits.getEmailInvocations() = ' + Limits.getEmailInvocations()
);
MySample.sendEmail();
System.debug(
LoggingLevel.ERROR,
'after Limits.getEmailInvocations() = ' + Limits.getEmailInvocations()
);
}

У тебя что-то такое есть посмотреть?

[code]public void execute(Database.BatchableContext BC, List<Object> scope) {
    System.debug(
        LoggingLevel.ERROR, 
        'before Limits.getEmailInvocations() = ' +  Limits.getEmailInvocations()
    );
    MySample.sendEmail();
    System.debug(
        LoggingLevel.ERROR, 
        'after Limits.getEmailInvocations() = ' +  Limits.getEmailInvocations()
    );
}[/code]
У тебя что-то такое есть посмотреть?