diff --git a/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php b/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php
index 4d6a1c3b9563..a7ea2f7a794e 100644
--- a/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php
+++ b/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php
@@ -47,6 +47,37 @@ public function testRenderTemplate(): void {
     $this->assertStringContainsString('<p>Hello testRenderTemplate Abba Baab!</p>', $rendered['html']);
   }
 
+  public function getLocaleConfigurations(): array {
+    $yesPartials = ['partial_locales' => TRUE, 'uiLanguages' => ['en_US']];
+    $noPartials = ['partial_locales' => FALSE, 'uiLanguages' => ['en_US']];
+
+    $allTemplates = [];
+    $allTemplates['fr_FR'] = ['subject' => 'Bonjour', 'html' => 'Voila!', 'text' => '{contribution.total_amount}'];
+    $allTemplates['fr_CA'] = ['subject' => 'Bonjour Canada', 'html' => 'Voila! Canada', 'text' => '{contribution.total_amount}'];
+    $allTemplates['es_PR'] = ['subject' => 'Buenos dias', 'html' => 'Listo', 'text' => '{contribution.total_amount}'];
+    $allTemplates['th_TH'] = ['subject' => 'สวัสดี', 'html' => 'ดังนั้น', 'text' => '{contribution.total_amount}'];
+
+    $onlyTemplates = function(array $locales) use ($allTemplates) {
+      return CRM_Utils_Array::subset($allTemplates, $locales);
+    };
+
+    $rendered = [];
+    $rendered['fr_FR'] = ['subject' => 'Bonjour', 'html' => 'Voila!', 'text' => '100,00 $US'];
+    $rendered['fr_CA'] = ['subject' => 'Bonjour Canada', 'html' => 'Voila! Canada', 'text' => '100,00 $ US'];
+    $rendered['es_PR'] = ['subject' => 'Buenos dias', 'html' => 'Listo', 'text' => '100.00 $US'];
+    $rendered['th_TH'] = ['subject' => 'สวัสดี', 'html' => 'ดังนั้น', 'text' => '100.00 $US'];
+
+    $result = [/* settings, templates, preferredLanguage, expectMessage */];
+    $result['fr_FR matches fr_FR (partial-mode)'] = [$yesPartials, $allTemplates, 'fr_FR', $rendered['fr_FR']];
+    $result['fr_CA matches fr_CA (partial-mode)'] = [$yesPartials, $allTemplates, 'fr_CA', $rendered['fr_CA']];
+    $result['fr_FR falls back to fr_CA (partial-mode)'] = [$yesPartials, $onlyTemplates(['fr_CA']), 'fr_FR', $rendered['fr_CA']];
+    $result['fr_CA falls back to fr_FR (partial-mode)'] = [$yesPartials, $onlyTemplates(['fr_FR']), 'fr_CA', $rendered['fr_FR']];
+    $result['fr_FR matches fr_FR (exact-mode)'] = [$noPartials, $allTemplates, 'fr_FR', $rendered['fr_FR']];
+    // ^^ FIXME: Last one probably fails b/c `isUseSeparatorSettings()` depends on partial_locales
+    // TODO: Add more.
+    return $result;
+  }
+
   /**
    * Test that translated strings are rendered for templates where they exist.
    *
@@ -56,107 +87,12 @@ public function testRenderTemplate(): void {
    *
    * @throws \API_Exception|\CRM_Core_Exception
    * @group locale
+   * @dataProvider getLocaleConfigurations
    */
-  public function testRenderTranslatedTemplate_AllowPartialLocales(): void {
-    $cleanup = \CRM_Utils_AutoClean::swapSettings(['partial_locales' => TRUE, 'uiLanguages' => ['en_US']]);
-
-    $this->individualCreate(['preferred_language' => 'fr_FR']);
-    $contributionID = $this->contributionCreate(['contact_id' => $this->ids['Contact']['individual_0']]);
-    $messageTemplateID = MessageTemplate::get()
-      ->addWhere('is_default', '=', 1)
-      ->addWhere('workflow_name', '=', 'contribution_online_receipt')
-      ->addSelect('id')
-      ->execute()->first()['id'];
-
-    Translation::save()->setRecords([
-      ['entity_field' => 'msg_subject', 'string' => 'Bonjour'],
-      ['entity_field' => 'msg_html', 'string' => 'Voila!'],
-      ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'],
-    ])->setDefaults([
-      'entity_table' => 'civicrm_msg_template',
-      'entity_id' => $messageTemplateID,
-      'status_id:name' => 'active',
-      'language' => 'fr_FR',
-    ])->execute();
-
-    $messageTemplateFrench = MessageTemplate::get()
-      ->addWhere('is_default', '=', 1)
-      ->addWhere('workflow_name', '=', 'contribution_online_receipt')
-      ->addSelect('id', 'msg_subject', 'msg_html')
-      ->setLanguage('fr_FR')
-      ->setTranslationMode('fuzzy')
-      ->execute()->first();
-
-    $this->assertEquals('Bonjour', $messageTemplateFrench['msg_subject']);
-    $this->assertEquals('Voila!', $messageTemplateFrench['msg_html']);
-
-    $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
-      'workflow' => 'contribution_online_receipt',
-      'tokenContext' => [
-        'contactId' => $this->ids['Contact']['individual_0'],
-        'contributionId' => $contributionID,
-      ],
-    ]);
-    $this->assertEquals('Bonjour', $rendered['subject']);
-    $this->assertEquals('Voila!', $rendered['html']);
-    $this->assertEquals('100,00 $US', $rendered['text']);
-
-    // French Canadian should ALSO pick up French if there
-    //is no specific French Canadian.
-    $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
-      'workflow' => 'contribution_online_receipt',
-      'tokenContext' => [
-        'contactId' => $this->ids['Contact']['individual_0'],
-        'contributionId' => $contributionID,
-      ],
-      'language' => 'fr_CA',
-    ]);
-    $this->assertEquals('Bonjour', $rendered['subject']);
-    $this->assertEquals('Voila!', $rendered['html']);
-    // Money is formatted per fr_FR locale as that is the found-template-locale.
-    $this->assertEquals('100,00 $US', $rendered['text']);
-
-    Translation::save()->setRecords([
-      ['entity_field' => 'msg_subject', 'string' => 'Bonjour Canada'],
-      ['entity_field' => 'msg_html', 'string' => 'Voila! Canada'],
-      ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'],
-    ])->setDefaults([
-      'entity_table' => 'civicrm_msg_template',
-      'entity_id' => $messageTemplateID,
-      'status_id:name' => 'active',
-      'language' => 'fr_CA',
-    ])->execute();
-
-    // But, prefer French Canadian where both exist.
-    $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
-      'workflow' => 'contribution_online_receipt',
-      'tokenContext' => [
-        'contactId' => $this->ids['Contact']['individual_0'],
-        'contributionId' => $contributionID,
-      ],
-      'language' => 'fr_CA',
-    ]);
-    $this->assertEquals('Bonjour Canada', $rendered['subject']);
-    $this->assertEquals('Voila! Canada', $rendered['html']);
-    // Note that as there was a native-Canada format the money-formatting is
-    // also subtly different.
-    $this->assertEquals('100,00 $ US', $rendered['text']);
-  }
-
-  /**
-   * Test that translated strings are rendered for templates where they exist.
-   *
-   * This system has a relatively closed localization policy where translations will only be
-   * used if the locale is fully supported by the app. Ex: Even though there are some strings
-   * for 'fr_FR', the language in "Admin=>Localizaton", so we don't use it.
-   *
-   * @throws \API_Exception|\CRM_Core_Exception
-   * @group locale
-   */
-  public function testRenderTranslatedTemplate_OnlyFullLocales(): void {
-    $cleanup = \CRM_Utils_AutoClean::swapSettings(['partial_locales' => FALSE, 'uiLanguages' => ['en_US']]);
+  public function testRenderTranslatedTemplate($settings, $templates, $preferredLanguage, $expectRendered): void {
+    $cleanup = \CRM_Utils_AutoClean::swapSettings($settings);
 
-    $this->individualCreate(['preferred_language' => 'fr_FR']);
+    $this->individualCreate(['preferred_language' => $preferredLanguage]);
     $contributionID = $this->contributionCreate(['contact_id' => $this->ids['Contact']['individual_0']]);
     $messageTemplateID = MessageTemplate::get()
       ->addWhere('is_default', '=', 1)
@@ -164,27 +100,31 @@ public function testRenderTranslatedTemplate_OnlyFullLocales(): void {
       ->addSelect('id')
       ->execute()->first()['id'];
 
-    Translation::save()->setRecords([
-      ['entity_field' => 'msg_subject', 'string' => 'Bonjour'],
-      ['entity_field' => 'msg_html', 'string' => 'Voila!'],
-      ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'],
-    ])->setDefaults([
-      'entity_table' => 'civicrm_msg_template',
-      'entity_id' => $messageTemplateID,
-      'status_id:name' => 'active',
-      'language' => 'fr_FR',
-    ])->execute();
+    foreach ($templates as $tplLocale => $tplData) {
+      Translation::save()->setRecords([
+        ['entity_field' => 'msg_subject', 'string' => $tplData['subject']],
+        ['entity_field' => 'msg_html', 'string' => $tplData['html']],
+        ['entity_field' => 'msg_text', 'string' => $tplData['text']],
+      ])->setDefaults([
+        'entity_table' => 'civicrm_msg_template',
+        'entity_id' => $messageTemplateID,
+        'status_id:name' => 'active',
+        'language' => $tplLocale,
+      ])->execute();
+    }
 
-    $messageTemplateFrench = MessageTemplate::get()
+    $myMessageTemplate = MessageTemplate::get()
       ->addWhere('is_default', '=', 1)
       ->addWhere('workflow_name', '=', 'contribution_online_receipt')
-      ->addSelect('id', 'msg_subject', 'msg_html')
-      ->setLanguage('fr_FR')
+      ->addSelect('id', 'msg_subject', 'msg_html', 'msg_text')
+      ->setLanguage($preferredLanguage)
       ->setTranslationMode('fuzzy')
       ->execute()->first();
 
-    $this->assertStringNotContainsString('Bonjour', $messageTemplateFrench['msg_subject']);
-    $this->assertStringNotContainsString('Voila!', $messageTemplateFrench['msg_html']);
+    // In our examples, subject+html are constant values, but text has tokens.
+    $this->assertEquals($expectRendered['subject'], $myMessageTemplate['msg_subject']);
+    $this->assertEquals($expectRendered['html'], $myMessageTemplate['msg_html']);
+    $this->assertNotEquals($expectRendered['text'], $myMessageTemplate['msg_text']);
 
     $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
       'workflow' => 'contribution_online_receipt',
@@ -193,9 +133,10 @@ public function testRenderTranslatedTemplate_OnlyFullLocales(): void {
         'contributionId' => $contributionID,
       ],
     ]);
-    $this->assertStringNotContainsString('Bonjour', $rendered['subject']);
-    $this->assertStringNotContainsString('Voila!', $rendered['html']);
-    $this->assertStringNotContainsString('100,00', $rendered['text']);
+    $this->assertEquals(
+      CRM_Utils_Array::subset($expectRendered, ['subject', 'html', 'text']),
+      CRM_Utils_Array::subset($rendered, ['subject', 'html', 'text'])
+    );
   }
 
   /**