Call a method only once within XCUITest in Swift 4 - swift

My test suite contains some test cases. I have some private functions where I will check elements existence. Consider I have three test cases:
func test_1() {
...
checkListViewElements()
...
}
func test_2() {
...
}
func test_3() {
...
checkListViewElements()
...
}
private func checkListViewElements() {
//Checking existence
}
Since I consider each test case as independent, the private function checkListViewElements() may get repeat within the test cases.
Problem:
When I run the whole test suite, all the three test cases(test_1, test_2 and test_3) will be executed.
The private method checkListViewElements() will be called twice. This will result with the increased amount of test suite completion time.
What I wanted:
I have so many functions like checkListViewElements() within my code. I want them to run only once when I run the whole test suite. (Remember, for each test case, the application terminates and open freshly)
What I tried:
var tagForListViewElementsCheck = "firstTime" //Global variable
private func checkListViewElements() {
if tagForListViewElementsCheck == "firstTime" {
//Checking existence
tagForListViewElementsCheck = "notFirstTime"
}
else {
//Skip
}
}
If I use local variables as tag, it works fine. But here, I have to create each tag for each private method. I really hated that.
I tried with dispatch_once and it seems not supported in Swift 4
Then I tried with static structs by referring this. It also does not seems working.
If there is any other nice approach to do it? Thanks in advance!

You may use function func setUp(). Its call only once per suite. More info at What is the purpose of XCTestCase's setUp method?.

Related

Bound variable in ViewModel is not updating the displayed value

I was trying to create an countdown timer in ViewModel but i didnt found any method to do that so i ve tried to do this with task delay and while loop but it ends after first task delay. Do u know any other way how to do that or how to repair that one.
public PageViewModel()
{
MethodName();
}
public async void MethodName()
{
CountSeconds = 10;
while (CountSeconds > 0)
{
await Task.Delay(1000);
CountSeconds--;
}
}
The reason why you can`t see others is related to context. You trying to run async code in non-async context.
To solve this problem you can do several ways, which way to choose is your choice and depends on your needs:
await MethodName();
async Task MethodName()
{
CountSeconds = 10;
while (CountSeconds > 0)
{
await Task.Delay(1000);
CountSeconds--;
}
}
Another way is to create various of tasks and execute them, here you can see methods, which can help you.
And as Rand Random metioned it's not about MAUI, it`s about understanding of async programming itself, so for you will be usefull read more about it.
You can use Dispatacher.StartTimer() (available in the DispatcherExtensions class) to create a function that will execute every x seconds/minutes/hours (depending of what you're setting) using the device's clock.
To access the Application's Dispatcher from any class, use the following line:
var dispatcher = Application.Current.Dispatcher;
Since there is no documentation available yet for MAUI, you can read the Device.StartTimer() documentation from Xamarin, which acts exactly the same.

kotlin coroutine - what is default scope?

How does coroutines default scope work if i do not specify anything. lets take a look at this example:
class MyAppCompatActivity:AppCompatActivity{
fun getContact() {
GlobalScope.launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) {
phoneContact.value = contact }
}
}
}
which simply updates the UI when a contact is retrieved. this is added to the global scope of so the coroutine life span can be that of the entire application.
but lets do the same thing again without a globalScope:
class MyAppCompatActivity:AppCompatActivity{
fun getContact() {
launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) {
phoneContact.value = contact }
}
}
}
what is the lifespan of getContact now that i have removed the globalScope ? is it tied to the MyAppCompatActivity scope ?
Your code will fail to compile because launch must be called on a CoroutineScope object. This object specifies the lifespan of the coroutine. Since your activity does not implement a scope it will fail to compile or call a completely unrelated launch function.
I don't think this is a good idea anymore, as it looks like they're just functions for testing (doesn't launch coroutines). Maybe this was an API available previously, but now you should be using lifecycleScope to scope a coroutine to a fragment or activity, and viewModelScope to scope them to a View Model's life cycle. These are properties available in those classes by already.
Here's what I see when I try to use launch:

How to use addClause() outside setup() in Laravel Backpack?

Say we have the UserCrudController like so:
public function setup()
{
// ...
// This works:
$this->crud->addClause('active');
// ...
}
The addClause() works fine. Now say we add it outside the setup():
public function posts()
{
// ...
// This DOES NOT work:
$this->crud->addClause('active');
// ...
}
Calling addClause() outside like this works, but if its inside a logic, it does not:
public function setup()
{
// This works:
$this->applyQueries();
}
private function applyQueries()
{
// This works:
$this->crud->addClause('active');
// This DOES NOT work:
if (true)
$this->crud->addClause('active');
}
Recap: I need to call addClause() from another function and inside a logic. How?
If you're creating a custom method, there's no way for Backpack to know what you want to do inside that method. Only what you write inside it will happen, in addition to what's in setup(), which is called in the __constructor().
Depending on your use case (list/create/edit/preview/etc), I recommend you take a look at the logic inside Backpack's CrudController. The methods there contain the logic for the operations above, and do use the addClause(). Copy-paste whatever you need to your posts() method. You'll basically be able to use the query where the clauses have been added by taking advantage of the $this->crud object, so the query would be $this->crud->query.

Current test case success/failure

I have a XCTestCase that is writing some asset that I would like to clean if it success. I discover that there is a static tearDown() method that I can override which is executed at the end of the test case. How can I know if the test case succeeded or not?
XCTestObserver is now deprecated so you should use the XCTestObservationCenter.
You should implement an observer that conforms to XCTtestObservation.
XCTestObservationCenter.sharedTestObservationCenter().addTestObserver(observer)
Apple's staff quote in XCTestObservation.swift:
Hooks for being notified about progress during a test run.
You can find how to handle testCaseDidFinish in Print Observer
func testCaseDidFinish(_ testCase: XCTestCase) {
let testRun = testCase.testRun!
let verb = testRun.hasSucceeded ? "passed" : "failed"
// FIXME: Apple XCTest does not print a period after "(N seconds)".
// The trailing period here should be removed and the functional
// test suite should be updated.
printAndFlush("Test Case '\(testCase.name)' \(verb) (\(formatTimeInterval(testRun.totalDuration)) seconds).")
}
XCTest has a property, testRun, which returns the XCTestRun for your test, which has a hasSucceeded property.
http://masilotti.com/xctest-documentation/Classes/XCTestRun.html

Good way to repeat a test, inserting an extra action?

I like the way Catch has nested hierarchies of tests, and it works through the combinations. It feels more natural than the setup/teardown of xUnit frameworks.
I now have a set of tests. What I want to do, about halfway down is insert a load/save serialization test, and then repeat all the tests below that point, first without the load/save, then again using the data it loaded from the serialization process. I.e. to prove that the load/save was correct.
I cannot get my head around if Catch has anything that can help with this? If it was phpUnit, I would be thinking about a string of #depends tests, and use a #dataProvider with a boolean input. A bit ugly.
(If that does not make sense, let me know, and I'll try to work out a minimal example)
The issue here is that Catch is designed to descend a tree-like organisation of tests and it automatically discovers all of the leaf-nodes of the structure and calls back into the test cases with untested code paths until they're all tested. The leaf nodes (tests, sections) are meant to be independent.
It sounds like you want to test a repository - something that can persist some data and then load it back in.
To repeat the exact same tests in two different scenarios (before serialisation, after serialisation) you'd need to put the same tests into some common place and call into that place. You can still use the same Catch macros in a non-test-case function, as long as you call it from a test case.
One possible way to do this is:
struct TestFixture {
Data data;
Repository repository;
TestFixture() : data(), instance() { }
};
void fillUpData(Data& data) {
// ...
}
void isDataAsExpected(Data& data) {
// Verify that 'data' is what we expect it to be, whether we
// loaded it or filled it up manually
SECTION("Data has ...) {
REQUIRE(data...);
}
}
TEST_CASE_METHOD(TestFixture, "Test with raw data") {
fillUpData(data);
isDataAsExpected(data);
REQUIRE(repository.save(data));
}
TEST_CASE_METHOD(TestFixture, "Operate on serialised data") {
REQUIRE(repository.load(data));
isDataAsExpected(_data);
}
One possible alternative is to supply your own main and then use command-line arguments to control whether/not the data is first serialised.
There's a third way I can think of that uses a non-quite-ready-yet feature of Catch - Generators:
TEST_CASE("...") {
using Catch::Generators;
int iteration(GENERATE(values(0, 1)));
const bool doSave(iteration == 0);
const bool doLoad(iteration == 1);
Repository repository;
Data data;
if (doLoad) {
REQUIRE(repository.load(data));
} else {
// fill up data
}
REQUIRE(..data..test..);
if (doSave) {
REQUIRE(repository.save(data));
}
}
The advantage of this method is you can see the flow and the test runs twice (for the two values) but the major disadvantage is that Generators are incompatible with SECTIONs and BDD-style features.