Why private var in viewModel with mutableStateOf is used for - android-jetpack-compose

I have seen some tutorials which declare mutableState in this way:
class SomeViewModel {
private val _loadingMap = mutableStateOf(false)
val loadingMap = _loadingMap
}
What would be the advantage about it?
I'm using my mutableStates just like this:
class SomeViewModel {
val loadingMap = mutableStateOf(false)
}
should I use the first code structure? or is a overkill implementation

Related

How to create a Page/Screen Object Model in Jetpack Compose Testing

For basic testing, if I create a test class like below, it works fine.
class MyComposeTest {
#get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()
#Test
fun myTest() {
composeTestRule.onNodeWithText("Login").performClick()
composeTestRule.onNodeWithText("Home").assertIsDisplayed()
}
}
But what if i want to abstract some of these into separate classes for an end-to-end test?
e.g. I want to create a login page class with all locators for Login and similarly for Home page and simplify my test as
#Test
fun myTest() {
val login = LoginPage()
val home = HomePage()
login.loginBtn.performClick()
home.homeTxt.assertIsDisplayed()
}
I am not sure how my page classes (with locators) should look like to make this possible.
You should pass the composeTestRule in the page's constructor. The code would look like this:
class BaseTestSuite {
#get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()
}
class LoginPage(composeTestRule: ComposeContentTestRule) {
val loginBtn = onNodeWithText("Login")
fun tapLoginButton() {
loginBtn.performClick()
}
}
class MyTestSuite() : BaseTestSuite {
val loginPage = LoginPage(composeTestRule)
#Test
fun myTest() {
loginPage.tapLoginButton()
// rest of the code
}
}

Published object not publishing, am I doing it wrong?

My code looks like this:
final class MyModelController: ObservableObject {
#Published var model = MyModel()
}
enum ButtonSelection: Int {
case left, right
}
final class MyModel {
var buttonSelection: ButtonSelection?
}
I have injected an instance of MyModelController as an #EnvironmentObject into my SwiftUI views.
When I set myModelController.model.buttonSelection, I thought it would update myModelController.model and send out an update because it's marked as #Published. However, it doesn't. How can I fix this?
#Published only detects changes for value types. MyModel is a class, which is a reference type.
If possible, changing MyModel to a struct will fix this. However, if this is not possible, see the rest of this answer.
You can fix it with Combine. The below code will update MyModelController when model (now an ObservableObject) changes.
final class MyModelController: ObservableObject {
#Published var model = MyModel()
init() {
_ = model.objectWillChange.sink { [weak self] in
self?.objectWillChange.send()
}
}
}
/* ... */
final class MyModel: ObservableObject {
#Published var buttonSelection: ButtonSelection?
}

Make class type a Dictionary key (Equatable, Hashable)

Say I have a class named LivingCreature
And other classes that inherit from it:
Human
Dog
Alien
This is what I'm trying to accomplish:
let valueForLivingCreature = Dictionary<Alien, String>
And access it like so:
let alienValue = livingCreatureForValue[Alien]
But this means the class should conform to Equatable and Hashable, but the class itself, not the class instance.
I've tried various ways of accomplishing this, but no luck.
As a compromise I've came up with is:
typealias IndexingValue = Int
class LivingCreature {
static var indexingValue: IndexingValue = 0
}
And then I can use the class as a key like so:
let livingCreatureForValue = Dictionary<IndexingValue, String>
Access:
let alienValue = livingCreatureForValue[Alien.indexingValue]
But, this way the IndexingValue should be set per class, by hand.
I would like to make a hash from the class itself like so:
class LivingCreature {
static var indexingValue: IndexingValue {
return NSStringFromClass(self).hash
}
}
This is not possible because self is not accessible is static var.
My question is, is there a better way of addressing this kind of issue?
Edit:
#Paulw11 Asked me why not make LivingCreature confirm to Equatable and Hashable,
The reason is I would not be able to access the value by the class type reference.
I would have to alloc an instance every time:
let alienValue = livingCreatureForValue[Alien()]
I do not want to call "Alien()" every time for finding a value.
And the component that uses it, doesn't care about the livingCreature instance, only about the class type.
I assume your are trying something like:
let valueForLivingCreature = Dictionary<LivingCreature.Type, String>
and:
let alienValue = valueForLivingCreature[Alien.self]
Then you can use ObjectIdentifier:
class LivingCreature {
class var classIdentifier: ObjectIdentifier {
return ObjectIdentifier(self)
}
//...
}
class Human: LivingCreature {
//...
}
class Dog: LivingCreature {
//...
}
class Alien: LivingCreature {
//...
}
let valueForLivingCreature: Dictionary<ObjectIdentifier, String> = [
Human.classIdentifier: String(Human),
Dog.classIdentifier: String(Dog),
Alien.classIdentifier: String(Alien),
]
let alienValue = valueForLivingCreature[Alien.classIdentifier] //->"Alien"
But in most use cases when you want to use meta-class as a dictionary key, you can find another way around:
class LivingCreature {
class var classValue: String {
return String(self)
}
//...
}
class Human: LivingCreature {
//...
//Override `classValue` if needed.
}
class Dog: LivingCreature {
//...
}
class Alien: LivingCreature {
//...
}
let alienValue = Alien.classValue //->"Alien"

Instantiating IOptions<> in xunit

I'm trying to write an xunit test for a class (in a .net Core project) that looks something like:
public Class FoodStore:IFoodStore
{
FoodList foodItems;
public FoodStore(IOptions<FoodList> foodItems)
{
this.foodItems = foodItems;
}
public bool IsFoodItemPresentInList(string foodItemId)
{
//Logic to search from Food List
}
}`
Note: FoodList is actually a json file, containing data, that is loaded and configured in the Startup class.
How can I write an xunit test with appropriate dependency injection to test the IsFoodItemPresentInList method ?
You can create an instance of IOptions<FoodList> using the Options.Create method:
var foodListOptions = Options.Create(new FoodList());
You could use OptionsWrapper<T> class to fake your configuration. Then you can pass in this object to your class that you want to test. That way you don't have to use DI or read the real configuration.
Something like this:
var myConfiguration = new OptionsWrapper<MyConfiguration>(new MyConfiguration
{
SomeConfig = "SomeValue"
});
var yourClass = new YourClass(myConfiguration);
I have encountered a similar problem (using xUnit), after some struggle, I worked it out.
The answer is so late, but should be helpful for others.
For your Question:
public Class FoodStoreTest
{
private readonly IConfigurationRoot _configuration;
private readonly IServiceProvider _serviceProvider;
public FoodStoreTest(){
// read Json
var configBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
_configuration = configBuilder.Build();
// SetUp DI
var services = new ServiceCollection();
services.AddOptions(); // this statement is required if you wanna use IOption Pattern.
services.Configure<YuntongxunOptions>(_configuration.GetSection("yuntongxun"));
_serviceProvider = services.BuildServiceProvider();
}
[Fact]
public void GetFootItemOption()
{
IOption<FoodList> optionAccessor = _serviceProvider.GetService<IOptions<FoodList>>();
FoodList footListOptions = optionAccessor.value;
Assert.NotNull(footListOptions)
// ...
}
}
Also, you should copy "appSettings.json" to your project root folder.
In a unit test, you typically don't use Dependency Injection, since it's you who controls the creation of the tested object.
To supply a suitable object that implements IOptions<FoodList> you can implement a fake class with the desired behavior yourself, or use some mocking framework to configure the instance on the fly, for example Moq.
As suggested by the other answers, in your test class you can create an options instance just for testing.
You can do it like this;
public class FakeFoodList : IOptions<FoodList>
{
public FoodList Value
{
get
{
return new FoodList(); // TODO: Add your settings for test here.
}
}
}
And then call it like this;
var foodOptions = new FakeFoodList();
var foodStore = new FoodStore(foodOptions);
var response = foodStore.Act();
Assert.Equal("whatever", response);

How to define array of closures in Swift?

I want to define like this:
public var reloadFRCsNeedToPerformWhenFail = [()->()]()
but I get an error
Like this:
public var reloadFRCsNeedToPerformWhenFail : [()->()] = []
If you use a type alias to make ()->() a type, you can do it your way:
public typealias VoidVoid = ()->()
public var reloadFRCsNeedToPerformWhenFail = [VoidVoid]()
Or, forego the [] shortcut notation and use the full generic:
public var reloadFRCsNeedToPerformWhenFail = Array<()->()>()

Resources