Можно поместить тесты в tests/
подкаталог приложения (а не tests.py
файл) и включать tests/models.py
с моделями только для теста.
Затем предоставляют выполняющий тест сценарий ( пример ), который включает Ваш tests/
"приложение" в INSTALLED_APPS
. (Это не работает, когда запущенное приложение тестирует из реального проекта, который не будет иметь тестового приложения в INSTALLED_APPS
, но я редко нахожу полезным запустить допускающие повторное использование тесты приложения из проекта, и Django 1.6 + не делает по умолчанию.)
( ПРИМЕЧАНИЕ : альтернативный динамический метод описал только ниже работ в Django 1.1 +, если Ваш тестовый сценарий разделяет на подклассы TransactionTestCase
- который значительно замедляет Ваши тесты - и больше не работает вообще в Django 1.7 +. Это оставляют здесь только для исторического интереса; не используйте его.)
В начале Ваших тестов (т.е. в методе установки, или в начале ряда doctests), можно динамично добавить "myapp.tests"
к установке INSTALLED_APPS и затем сделать это:
from django.core.management import call_command
from django.db.models import loading
loading.cache.loaded = False
call_command('syncdb', verbosity=0)
Затем в конце Ваших тестов, необходимо вымыться путем восстановления старой версии INSTALLED_APPS и очистки кэша приложения снова.
Этот класс инкапсулирует шаблон, таким образом, он не загромождает Ваш тестовый код вполне так же.
Моя реализация для повышения производительности приведена ниже. Это примерно в 4,5 раза быстрее, чем решение на основе DecimalFormatter: при запуске на моей машине с использованием Eclipse с приличной домашней тестовой системой результаты следующие:
Некоторые примечания:
Также: чтобы имитировать поведение оригинала (но не приведенного в комментариях), это:
package com.pragmaticsoftwaredevelopment.stackoverflow;
...
final static String formatterZeroes="00000000000000000000000000000000000000000000000000000000000";
protected static String getFormattedDecimal ( String value, int len, int scale, Boolean signed ) throws IllegalArgumentException {
if (value.length() == 0) throw new IllegalArgumentException ("Cannot format a zero-length value");
if (len <= 0) throw new IllegalArgumentException ("Illegal length (" + len + ")");
StringBuffer retVal = new StringBuffer();
String sign=null;
int numStartIdx;
if ("+-".indexOf(value.charAt(0)) < 0) {
numStartIdx=0;
} else {
numStartIdx=1;
if (value.charAt(0) == '-')
sign = "-";
}
if (signed && (value.charAt(0) != '-'))
sign = "+";
if (sign==null)
sign="";
retVal.append(sign);
int dotIdx = value.indexOf('.');
int requestedWholePartLength = (len-scale);
if (dotIdx < 0) {
int wholePartPadLength = (requestedWholePartLength - ((value.length()-numStartIdx)));
if (wholePartPadLength > 0)
retVal.append(formatterZeroes.substring(0, wholePartPadLength));
retVal.append (value.substring(numStartIdx));
if (scale > 0)
retVal.append(formatterZeroes.substring(0, scale));
}
else {
int wholePartPadLength = (requestedWholePartLength - (dotIdx - numStartIdx));
if (wholePartPadLength > 0)
retVal.append(formatterZeroes.substring(0, wholePartPadLength));
retVal.append (value.substring(numStartIdx, dotIdx));
retVal.append (value.substring (dotIdx+1));
int fractionalPartPadLength = (scale - (value.length() - 1 - dotIdx));
if (fractionalPartPadLength > 0)
retVal.append(formatterZeroes.substring(0, fractionalPartPadLength));
}
return retVal.toString();
}
Если вы для начала получаете ввод в виде String, зачем вам нужно преобразовывать его в BigDecimal и обратно?
Похоже, было бы намного быстрее найти позицию десятичной точки, сравните это с длиной / масштабом и дополните строку соответствующим образом.
Я согласен с ChssPly76 в отношении ручных манипуляций со строками.
Однако, если вы собираетесь перейти по маршруту BigDecimal
/ DecimalFormat
, вы можете рассмотреть возможность совместного использования своих DecimalFormat
s вместо создания нового по одному на каждой итерации. Обратите внимание, что эти классы не являются потокобезопасными, поэтому, если вы используете несколько потоков для обработки, вам нужно будет использовать что-то вроде хранилища ThreadLocal
для поддержки форматировщика на Thread
.
Кстати, вы проверили это и обнаружили, что производительность неприемлема, или вы просто ищете наиболее эффективное из возможных решений? Обратите внимание на то, что говорит Дональд Кнут по теме ранней оптимизации .