임의의 결과를 반환하는 함수를 사용한 단위 테스트
이것이 언어 나 프레임 워크에 국한된 것이라고 생각하지 않지만 xUnit.net과 C #을 사용하고 있습니다.
특정 범위에서 임의의 날짜를 반환하는 함수가 있습니다. 나는 날짜를 전달하고 반환 날짜는 항상 주어진 날짜보다 1 ~ 40 년 전입니다.
이제 이것을 단위 테스트하는 좋은 방법이 있는지 궁금합니다. 가장 좋은 방법은 루프를 만들고 함수를 100 번 실행하고이 100 개의 결과가 모두 원하는 범위에 있다고 주장하는 것 같습니다.
또한 랜덤 생성기를 제어 할 수없는 경우 완벽한 솔루션이 없다는 것을 알고 있지만 (결국 결과는 랜덤 임) 임의의 결과를 반환하는 기능을 테스트해야 할 때 어떤 접근 방식을 취해야하는지 궁금합니다. 특정 범위?
함수가 원하는 범위의 날짜를 반환하는지 테스트하는 것 외에도 결과가 잘 분산되어 있는지 확인하려고합니다. 설명하는 테스트는 단순히 보낸 날짜를 반환하는 함수를 통과합니다!
따라서 함수를 여러 번 호출하고 결과가 원하는 범위에 있는지 테스트하는 것 외에도 결과를 버킷에 넣고 버킷의 결과 수가 거의 동일한 지 확인하여 분포를 평가하려고합니다. 끝난. 안정적인 결과를 얻으려면 100 개 이상의 호출이 필요할 수 있지만 이것은 값 비싼 (런타임 현명한) 함수처럼 들리지 않으므로 몇 K 반복 동안 쉽게 실행할 수 있습니다.
나는 전에 균일하지 않은 "무작위"기능에 문제가 있었다. 그것들은 진짜 고통이 될 수있다. 초기에 테스트 할 가치가있다.
난수 생성기 모의 또는 가짜
이런 식으로 ... 컴파일하지 않았으므로 구문 오류가있을 수 있습니다.
public interface IRandomGenerator
{
double Generate(double max);
}
public class SomethingThatUsesRandom
{
private readonly IRandomGenerator _generator;
private class DefaultRandom : IRandomGenerator
{
public double Generate(double max)
{
return (new Random()).Next(max);
}
}
public SomethingThatUsesRandom(IRandomGenerator generator)
{
_generator = generator;
}
public SomethingThatUsesRandom() : this(new DefaultRandom())
{}
public double MethodThatUsesRandom()
{
return _generator.Generate(40.0);
}
}
테스트에서 IRandomGenerator를 가짜 또는 조롱하여 통조림 된 것을 반환하십시오.
이 문제에는 세 가지 측면이 있다고 생각합니다.
첫 번째 : 내 알고리즘이 올바른가요? 즉, 제대로 작동하는 난수 생성기가 주어지면 범위에 걸쳐 무작위로 분포 된 날짜를 생성할까요?
두 번째 : 알고리즘이 엣지 케이스를 올바르게 처리합니까? 즉, 난수 생성기가 허용 가능한 최고 또는 최저 값을 생성 할 때 문제가 발생합니까?
세 번째 : 알고리즘 구현이 작동합니까? 즉, 알려진 의사 난수 입력 목록이 주어지면 예상 의사 난수 날짜 목록이 생성됩니까?
처음 두 가지는 단위 테스트 도구 모음에 빌드 할 것이 아닙니다. 시스템을 설계하면서 증명할 수있는 것입니다. daniel.rikowski가 제안한 것처럼 수백만 개의 날짜를 생성하고 카이 제곱 테스트를 수행하는 테스트 도구를 작성하여이 작업을 수행 할 수 있습니다. 또한이 테스트 하네스가 두 가지 엣지 케이스를 모두 처리 할 때까지 종료되지 않았는지 확인합니다 (내 난수 범위가이 문제를 해결할 수있을만큼 충분히 작다고 가정). 그리고 저는 이것을 문서화하여 알고리즘을 개선하려는 모든 사람들이 그것이 파괴적인 변화라는 것을 알게 될 것입니다.
The last one is something I'd make a unit test for. I need to know that nothing has crept into the code that breaks its implementation of this algorithm. The first sign I'll get when that happens is that the test will fail. Then I'll go back to the code and find out that someone else thought that they were fixing something and broke it instead. If someone did fix the algorithm, it'd be on them to fix this test too.
You don't need to control the system to make the results deterministic. You're on the right approach: decide what is important about the output of the function and test for that. In this case, it is important that the result be in a range of 40 days, and you are testing for that. It's also important that it not always return the same result, so test for that too. If you want to be fancier, you can test that the results pass some kind of randomness test..
Normaly I use exactly your suggested approach: Control the Random generator. Initialize it for test with a default seed (or replace him by a proxy returning numbers which fit my testcases), so I have deterministic/testable behaviour.
If you want to check the quality of the random numbers (in terms of independance) there are several ways to do this. One good way is the Chi square test.
Depending on how your function creates the random date, you may also want to check for illegal dates: impossible leap years, or the 31st day of a 30-day month.
Methods that do not exhibit a deterministic behavior cannot be properly unit-tested,as the results will differ from one execution to another. One way to get around this is to seed the random number generator with a fixed value for the unit test. You can also extract the randomness of the date generation class (and thus applying the Single Responsibility Principle), and inject known values for the unit-tests.
Sure, using a fixed seed random number generator will work just fine, but even then you're simply trying to test for that which you cannot predict. Which is ok. It's equivalent to having a bunch of fixed tests. However, remember--test what is important, but don't try to test everything. I believe random tests are a way to try to test everything, and it's not efficient (or fast). You could potentially have to run a great many randomized tests before hitting a bug.
What I'm trying to get at here is that you should simply write a test for each bug you find in your system. You test out edge cases to make sure your function is running even in the extreme conditions, but really that's the best you can do without either spending too much time or making the unit tests slow to run, or simply wasting processor cycles.
I would recommend overriding the random function. I am unit testing in PHP so I write this code:
// If we are unit testing, then...
if (defined('UNIT_TESTING') && UNIT_TESTING)
{
// ...make our my_rand() function deterministic to aid testing.
function my_rand($min, $max)
{
return $GLOBALS['random_table'][$min][$max];
}
}
else
{
// ...else make our my_rand() function truly random.
function my_rand($min = 0, $max = PHP_INT_MAX)
{
if ($max === PHP_INT_MAX)
{
$max = getrandmax();
}
return rand($min, $max);
}
}
I then set the random_table as I require it per test.
Testing the true randomness of a random function is a separate test altogether. I would avoid testing the randomness in unit tests and would instead do separate tests and google the true randomness of the random function in the programming language you are using. Non-deterministic tests (if any at all) should be left out of unit tests. Maybe have a separate suite for those tests, that requires human input or much longer running times to minimise the chances of a fail that is really a pass.
I don't think Unit testing is meant for this. You can use Unit testing for functions that return a stochastic value, but use a fixed seed, in which case in a way they are not stochastic, so to speak, for random seed, I dont think Unit testing is what you want, for example for RNGs what you mean to have is a system test, in which you run the RNG many many times and look at the distribution or moments of it.
참고URL : https://stackoverflow.com/questions/311807/unit-testing-with-functions-that-return-random-results
'developer tip' 카테고리의 다른 글
SandCastle에서 만든 두 페이지를 하나의 메인 페이지로 병합 할 수 있습니까? (0) | 2020.11.09 |
---|---|
“이 UIView는 아무것도 모르는 NSISVariable의 대리자 인 것 같습니다. (0) | 2020.11.09 |
Java의 문자열 풀에 대한 질문 (0) | 2020.11.08 |
Java와 Core Java의 차이점은 무엇입니까? (0) | 2020.11.08 |
HtmlAgilityPack : 전체 HTML 문서를 문자열로 가져 오기 (0) | 2020.11.08 |