Help us understand the problem. What is going on with this article?

[Apex] 指定サイズのBlobデータを作成する

More than 3 years have passed since last update.

テストコードでファイル添付が可能なオブジェクト(添付ファイルやFeedItemなど)のテストデータを作成する時、指定サイズのファイルを添付したい… といった場合などに使えるネタです。

指定サイズのBlobデータを作成する方法

指定のバイト数分のString値を作成し、Blob型に変換します。

以下のサンプルでは、1MBのBlobデータを作成しています。
※本記事では1KB=1,000byteとして計算しています。1

Apex
Integer byteSize = (Integer)Math.pow(10, 6); // 1MBをbyteに換算 -> 1,000,000
String s = ('0').repeat(byteSize);           // 1バイト文字を繰り返し、1MB分の文字列を生成
Blob myBlob = Blob.valueOf(s);

System.debug(myBlob.size());                 // -> 1,000,000

作成可能なサイズの上限

以下のエラーが発生しないようにサイズを抑える必要があります。

  • String値を生成する際、String型で扱える文字列の長さの上限(6,000,000)を超えるとLimitExceptionが発生してしまいます。
/* 7MB分の文字列を作りたい */
Integer byteSize = (Integer)Math.pow(10, 6) * 7;  // -> 7,000,000
String s = ('0').repeat(byteSize);                 // System.LimitException: String is too long.
  • Blobデータを作成すると、その分ヒープサイズを消費します。Apexにはヒープサイズのガバナ制限2があり、上限を超えるとガバナ制限エラーが発生してしまいます。

以下のようにコードを変更すると String is too long エラーを回避できますが、ヒープサイズのガバナ制限に違反しているのでエラーが発生します。

/* 7MB分の文字列を作りたい */
Integer byteSize = (Integer)Math.pow(10, 6);  // 1MBをbyteに換算 -> 1,000,000
Blob myBlob = Blob.valueOf('');               // 空のBlobを作成
for(Integer i = 0; i < 7; i++){
  String s = ('0').repeat(byteSize);
  myBlob = Blob.valueOf(myBlob.toString() + Blob.valueOf(s).toString());  // -> System.LimitException: Apex heap size too large: 7001380
}

テストコードでの利用例

Apexトリガで1MBを超える添付ファイルの登録を禁止する処理に対して、テストコードは以下のように書くことができます。

添付ファイルのトリガ
trigger AttachmentTrigger on Attachment (before insert) {
  for(Attachment att:Trigger.new){
    // 1MBを超えるファイルの添付を禁止
    if(att.Body.size() > (Integer)Math.pow(10, 6)){
      att.BodyLength.addError('1MBを超えるファイルは添付できません');
    }
  }
}
テストメソッド
@isTest static void fileSizeExceededErrorTest() {
  // 添付ファイルの親レコードを作成
  Account acc = new Account(Name = 'Test Account');
  insert acc;

  Test.startTest();
  // 添付ファイルのBodyを作成
  Integer byteSize = (Integer)Math.pow(10, 6) + 1;  // 1MB + 1byte
  String bodyString = ('0').repeat(byteSize);
  // 添付ファイルレコードを作成
  Attachment att = new Attachment(
    Name = 'TestData.txt',
    Body = Blob.valueOf(bodyString),
    ParentId = acc.Id
  );

  String errorMsg;
  try{
    insert att;
  }catch(DmlException e){
    errorMsg = e.getDmlMessage(0);
  }
  Test.stopTest();

  System.assertEquals('1MBを超えるファイルは添付できません', errorMsg);  // OK

}

しかしファイルサイズの上限を10MBに引き上げたい場合、同じサイズのBlobデータを作ろうとすると前述のガバナ制限エラーが発生してしまいます。
これではテストケースの実行ができないため、Test#isRunningメソッドを使用してテスト実行時だけエラー条件を変えるという手があります。

添付ファイルのトリガ
trigger AttachmentTrigger on Attachment (before insert) {
  for(Attachment att:Trigger.new){
    // ファイルサイズをチェックする
    // 本番実行時は10MB、テスト実行時は10KBを超えていたらエラー
    //  -> テストコードでは10KBのBlobデータを作れば良い
    Integer bodySize = att.Body.size();
    Integer fileSizeLimit = (Integer)Math.pow(10, 6) * 10;
    Integer fileSizeLimitForTest = (Integer)Math.pow(10, 3) * 10;
    if(
      (!Test.isRunningTest() && bodySize > fileSizeLimit) || 
      (Test.isRunningTest() && bodySize > fileSizeLimitForTest)
    ){
        att.addError('10MBを超えるファイルは添付できません');
    }
  }
}

考慮事項

Salesforceプラットフォームはマルチテナントで動作しているため、テストのコードカバー率を上げるためだけに大量にヒープを消費することは避けるべきです。
ヒープサイズの上限近くまで大きなBlobデータを作るようなことはせず、上記サンプルのようなサイズを抑える手段を検討すると良いでしょう。

参考リンク


  1. Salesforce上で表示されるファイルサイズの表記は1KB=1024byteです。 

  2. 同期Apexは6MB、非同期Apexは12MB(Winter'16時点。参考:Apexガバナ制限) 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした