Swift Unit Test how to set with a private setter - swift

Here is a little background:
I am trying to test some functions. I CANNOT change anything in the function or any class variables.
So I am calling this function in my unit test, the problem is that, there is a boolean flag, this method simply will just not execute if this flag is not set to true. But this flag has a private setter, so I can directly set it.
I asked around someone told me to use a extension IN the test file to set the variable, but I've tried I don't think I can set it if the extension is not in the same file as the function. Am I doing something wrong? Or is there any other way to test it?

What they were referring to is to place an extension in the file with the class-under-test. So if you have something like:
class ToBeTested {
private(set) var bool: Bool
}
You can add an internal setter:
extension ToBeTested {
func setBoolTrue() { bool = true }
}
But this has to be in the same file with ToBeTested. If you cannot modify that file, this is not a solvable problem. If it needs to be tested this way, then the class will need to be designed to permit that.
When a property is marked private(set), the compiler can assume that the value cannot be changed in any way outside this file. That allows it to apply optimizations that may not be valid if the property were changeable outside this file. The "setter method" may not even exist if the compiler determines that it doesn't need it. For example, it may completely inline that operation, or eliminate it entirely if it can prove the value is never changed.

Related

When are static properties initialised in testing in Swift?

I have a class with an optional type property (static). I set this when I start to use the class. Obviously, when the program first starts, the property has no value.
My question is about testing. I expected the class to be initialised at the start of every test (i.e. the type property set back to having no value). However, it seems the class is initiated once at the beginning of all my tests and therefore the type property has the same value in all tests, which is not what I want.
What are the rules about class initialisation in testing? Is there any way I can force my class to "reset"?
Thanks,
Julian
As you've noticed, static properties on your test case are persistent throughout all your tests. However, XCTestCase has two sets of methods that you can override to customize this, called setUp() and tearDown(). It's somewhat confusing, since there are identically named class and instance methods for each of these; override the class methods to have something happen only once, and override the instance methods to make something happen before or after each individual test. In your case, it would probably make the most sense to override the instance method version of setUp() and have it reset your properties.

Boolean extension function

When I try to create Extension Function to set Boolean true or false like the below.
Boolean.setTrue(){
this = true
}
Boolean.setFalse(){
this = false
}
It says variable expected. How to achieve this.
You cannot change the value of this, this would break a lot of assumptions, even if you could you would not be able to change the value, as Booleans are immutable.
More generally, there is a fine line between simplifying code, and making it more complex, and in this case that would complicate it. I would agree that adding String.splitByDot() may make sense, but replacing idiomatic code tends to just make the code more complex, as you start to wonder why the code had to be replaced.
Sorry but this does not make sense. Just use myBool=false, it's what anyone understands and cannot get any more readable.
Also Boolean is immutable and what you're trying isn't possible anyways.
We have to be careful not to overuse extensions. It's one of the greatest features Kotlin (and others) offers, but in certain examples, e.g. trying to change the way a dead simple Boolean is being assigned, it's getting dangerous IMHO (luckily it's not possible).
Here is an extension method that works in C# 7.2 or later:
public static class Extensions
{
public static bool Toggle(ref this bool b) => b = !b;
}
Then elsewhere, something like this will work:
bool b1 = true; // Works for primitive bool type.
Boolean b2 = true; // Works for Boolean object, too.
b1.Toggle();
b2.Toggle();
The only benefit I see to using an extension method is to shorten lines with long bool expressions, such as replacing:
this.SomeObjectWithALongName.SomeVerboselyNamedProperty
= !this.SomeObjectWithALongName.SomeVerboselyNamedProperty
with
this.SomeObjectWithALongName.SomeVerboselyNamedProperty.Toggle();
I don't know what drawbacks this extension method may have.
The reason you can't do this is that you cannot reassign the receiver in an extension function.
It's not possible to change the value of the Boolean because it is immutable.
The reason you can do this comes to a lack of implementation of Kotlin extension probably due to the fact Extension in Kotlin are resolved Statically (even probably really static).
So 'this' in a static context doesn't make sense.

Different ways of making read public write private variables in swift?

I've completed a online course that taught us to write properties of classes as:
class bar {
private var _foo:Int
var foo {
return _foo
}
}
Since then i've seen
class bar {
private (set) var foo:Int
}
Is there any difference between these two ways of writing things, and which would be best practise?
The second option is simpler and clearer and it has the added benefit of still being able to add get, set, willSet, and didSet blocks on the property while still having clearly defined scope on the getter and setter. Of course you can still add those to the private property but I think the code starts to get less readable.
Also note that the first option is a public read-only computed property making use of a private stored property.
The second option can be either a computed or stored property.

How do I check if a variable is declared in Swift?

I know that if a variable is declared it is easy to test whether or not it is null, but I can't find a way to work out if a variable is declared at all. What I need is:
If variable is declared:
var i:Int
if [i is declared] {
// returns true
}
If variable is not declared:
if [i is declared] {
// returns false (but does not crash)
}
Use case: I am writing an app to teach people Swift. I want to be able to evaluate their code and make sure it is correct. So my instruction might be 'create a variable called i and set it equal to 1' and I want to test if they have done that correctly. In PHP I can do isset($i), I need an equivalent in Swift. I can't use if i == null because as simpleBob says that will crash if is not defined.
Thanks in advance!
Rob
If you are just looking to see if there is a variable by a certain name in a class, you could simply start typing the variable name in that class and it should auto-populate.
However, as simpleBob mentioned, the code will not compile if variables are used before their declaration.
Updated
I am not sure how you have the users entering data, however, if they are entering it into a UITextView, you could grab the .containsString property and see if they put in the variable as you asked.
if myTextView.text.containsString("var i = 1")
{
print("They entered it correctly.")
}
else
{
// Do Something
}
You could even chain those to include other variations they would use.
I hope this helps.

Why is 'init' not assignable?

I just read that the init method can't be used as a value. Meaning:
var x = SomeClass.someClassFunction // ok
var y = SomeClass.init // error
Example found on Language reference
Why should it be like that? Is it a way to enforce language level that too dirty tricks come into place, because of some cohertion or maybe because it interferes with another feature?
Unlike Obj-C, where the init function can be called multiple times without problems, in Swift there actually is no method called init.
init is just a keyword meaning "the following is a constructor". The constructor is called always via MyClass() during the creation of a new instance. It's never called separately as a method myInstance.init(). You can't get a reference to the underlying function because it would be impossible to call it.
This is also connected with the fact that constructors cannot be inherited. Code
var y = SomeClass.init
would also break subtyping because the subtypes are not required to have the same initializers.
Why should it be like that?
init is a special member, not a regular method.
Beyond that, there's no reason that you'd ever need to store init in a variable. The only objects that could use that function in a valid way are instances of the class where that particular init is defined, and any such object will have already been initialized before you could possibly make the assignment.
Initializers don't have a return value. In order to assign it to something, it should be able to return something - and it doesn't.