Can I run an XCTest suite multiple times? - xcode

Is it possible to have Xcode run your unit tests multiple times?
I had an issue in several unit tests that caused intermittent failures. Now that I think I've fixed it, my only option appears to mash ⌘ + U until I'm 95% confident the bug is gone.
I know other unit testing frameworks make it quite easy to run a single test, test case, or test suite multiple times. Do we have this luxury in XCTest yet?

For me it works in swift
override func invokeTest() {
for time in 0...15 {
print("this test is being invoked: \(time) times")
super.invokeTest()
}
}

Try overriding invoke test: https://developer.apple.com/documentation/xctest/xctestcase/1496282-invoketest?language=objc
- (void)invokeTest
{
for (int i=0; i<100; i++) {
[super invokeTest];
}
}

It might help you to use
func testMultiple() {
self.measureBlock() {
...
XCTAssert(errMessage == nil, "no error expected")
}
}
This runs the code inside self.measureBlock() multiple times to measure the average time.
It is work to change the code, but you might want to know the execution time anyways.
This answer might be close enough to what you want and it is easy to do.

One alternative is to do this via the command line. You can run a single test using the -only-testing argument, and avoid building using test-without-building i.e. (new lines added for clarity)
for i in {1..10}; \
do xcodebuild \
test-without-building \
-workspace MyApp.xcworkspace \
-scheme Debug \
-destination 'platform=iOS Simulator,OS=11.2,name=iPhone 8' \
-only-testing:MyApp.Tests/TestFile/myTest;
done

Try using a for loop:
func testMultiple() {
for _ in 0...100 {
...
XCTAssert(errMessage == nil, "no error expected")
}
}
Note this doesn't work within a self.measureBlock(). You'll get an NSInternalConsistencyException: Cannot measure metrics while already measuring metrics
However, you can CALL this within a measureBlock():
func testMultiple() {
for _ in 0...100 {
...
XCTAssert(errMessage == nil, "no error expected")
}
}
func testPerformance() {
self.measureBlock() {
self.testMultiple()
}
}
Xcode 8 runs the measureBlock code 10 times.

I had used the invokeTest() override in the past (Xcode 10) with great success. But now in Xcode 11 its not working (for me at least). What I ended up doing was:
func test99Loop() {
for i in 0..<LOOP_COUNT {
if i > 0 { tearDown(); sleep(1); setUp() }
test3NineUrls()
do { tearDown(); sleep(1) }
setUp()
test6NineCombine()
print("Finished Loop \(i)")
}
}
I obviously use setup/teardown, and this is the proper way to do those multiple times (since the first and last are called by Xcode).

You can now do this in Xcode
Edit the Test Plan. In the Test Navigator, at the top you should see "Test Plan: MyAppName (Default)". Tap on this and select "Edit Test Plan".
In the editor, select Configurations, Configuration 1
Under Test Execution you can set Test Repetition Mode and Maximum Test Repetitions.
Run the tests from the menu Product > Test

Xcode has a built-in way you can do this:
Right-click the test and select Run <test> Repeatedly...
That menu has a few configurations, one of them is Stop After where you can select Failure which will stop the execution if it failed during one of the repetitions.
You can also run a test class or the whole test suite repeatedly.

Related

Parallel execution 'mvn test' in Jenkins

I try to create jenkinsfile for parallel execution command mvn test with different arguments. On the first stage of jenkinsfile I create *.csv file where are will be future arguments for mvn test command. Also I don't know the quantity of parallel stages (it depends on first stage where I get data from DB). So, summarize it again. Logic:
First stage for getting data from DB over command mvn test (with args). On this test I save data into csv file.
In loop of jenkinsfile I read every string, parse it and get args for arallel execution mvn test (with args based on the parsed data).
Now it looks like this (only necessary fragments of jenkinsfile):
def buildProject = { a, b, c ->
node {
stage(a) {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh "mvn -Dtest=test2 test -Darg1=${b} -Darg2=${c}"
}
}
}
}
stages {
stage('Preparation of file.csv') {
steps {
sh 'mvn -Dtest=test1 test'
}
}
stage('Parallel stage') {
steps {
script {
file = readFile "file.csv"
lines = file.readLines()
def branches = [:]
for(i = 0; i < lines.size(); i++) {
values = lines[i].split(';')
branches["${values[0]}"] = { buildProject(values[0], values[1], values[2]) }
}
parallel branches
}
}
}
}
So, which problems do I face now with?
I see in log following error:
[ERROR] The goal you specified requires a project to execute but there is no POM in this directory (/Data/jenkins/workspace//#2)
I look at workspaces of Jenkins and see that there were created several empty(!!!) directories (quantity equals to quantity of parallel stages). And therefore mvn command could be executed because of absence of pom.xml and other files.
In branches the same data are saved on every iteration of loop and in 'stage(a)' I see the same title (but every iteration of loop has unique 'values[0]').
Can you help me with this issue?
Thank you in advance!
So, regarding this jenkins issue issues.jenkins.io/browse/JENKINS-50307 and workaround which could be found there, task could be closed!

How to run single maven test with spaces within name

Normally using maven when I want to run a single test I would do something like this....
mvn clean test -Dtest= GetRegistrationValidatorTest#MyTestName
We have just changed our Groovy test names to be more meaningful using the following type of syntax.
class GetRegistrationValidatorTest {
#Test
void 'validation get registration chassis number success'() {
}
}
How can I run the single maven test when it is named as per above?
thanks
mvn clean test -Dtest='GetRegistrationValidatorTest#MyTestName'
Single quotes work for me, even with stranger characters than spaces:
class PlopTest {
#Test void 'Hey! Can you plöp?'() {
println "Sure..."
}
#Test void foo() {
assertTrue(false);
}
}
Then:
% mvn test -Dtest='PlopTest#Hey! Can you plöp?'
[...]
Running PlopTest
Sure...
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.91 sec
1 test run, no failure => it correctly executed only the single test I passed as argument.
If I try -Dtest='PlopTest' it runs both tests (and of course fails).

how to get test timing information from gradle output during build?

I would like to get timing information on how long it took a whole *.java class to run AND timing information on each test as well in the gradle output. Is there a way to do that with gradle?
Currently, I just have
beforeTest{ descr ->
logger.warn("Starting Test ${descr.className} : ${descr.name}")
}
It depends on your intent. For debugging purposes, I usually run gradle with --profile flag, which generates the full report of task execution times. See Gradle Command Line.
If you wish to do something ad-hoc with times, you'd need to code the desired behavior. For example, this will print execution time for each test:
test {
afterTest { descriptor, result ->
def totalTime = result.endTime - result.startTime
println "Total time of $descriptor.name was $totalTime"
}
}
See also:
Testing
TestResult
A variation of the accepted answer with rounding millis to seconds:
test {
afterSuite { descriptor, result ->
def duration = java.util.concurrent.TimeUnit.MILLISECONDS
.toSeconds(result.endTime - result.startTime)
println "Total duration of $descriptor: $duration seconds"
}
}

Recursion and Xcode 7 compile error

this is a simple recursion function
func recursion(parameter : Double)
{
if parameter < 12
{
recursion(parameter + 1)
}
print(parameter)
}
when i am trying to put a simple value for example 0 or 1
recursion(0)
i get a compile error saying Missing argument for #1 in call any idea why this is happening?
btw if i change the function to
func recursion(parameter : Double)
{
if parameter > 1
{
recursion(parameter - 1)
}
print(parameter)
}
everything works fine
any ideas? i am using Xcode 7 beta
Your code works fine, just make a Clean & Build and then try it again and the initial compile error should disappear. Remember that Xcode 7 is still in Beta, Apple is working to fix this kind of false compile errors properly.
I hope this help you.

Scala IDE Debugger "step into" behavior

Current behavior:
Put a breakpoint on the case Twice(n) ... line.
On "step into" the control goes to x match { line
On "step into" the control goes to def TwiceTest = { line
On further "step into" the control goes to if (z % 2 == 0)... line.
Expected behavior:
Put a breakpoint on the case Twice(n) ... line.
On "step into" the control goes to if (z % 2 == 0)... line.
Code Snippet
object testobj extends App {
def TwiceTest = {
val x = Twice(21)
x match {
case Twice(n) => Console.println(n)
} // prints 21
}
TwiceTest
}
object Twice {
def apply(x: Int): Int = x * 2
def unapply(z: Int): Option[Int] = {
if (z % 2 == 0) Some(z / 2) else None
}
}
The current behavior is irritating while debugging a scala program with lots of nested extractors. I tried this with the new Scala debugger as well as the Java debugger but with the same result.
Step Filtering also does not help in this case.
As a workaround, I am putting a breakpoint in the unapply method and running resume from the first breakpoint. Can someone please suggest me a cleaner method.
Edit 1
I am using Scala-IDE (latest nightly build. 2.1.0.nightly-2_09-201208250315-529cd70 )
Eclipse Version: Indigo Service Release 2 Build id: 20120216-1857
OS: Windows 7 ( 64 bit)
The line number information in the bytecode is wrong. It is not an issue with the IDE, but the Scala compiler. When pattern matching is compiled, synthetic code sometimes gets the wrong position information.
I assume you are using Scala 2.9.2. In the next version of Scala (2.10.0), there are significant improvements in the pattern matcher, so it would be good to give it a try.

Resources