#AddTrace(name = "getCustomers")
override suspend fun getCustomers(isDeleted: Boolean): List<Customer> {}
The code requires FirebaseApp and FirebasePerf but I don't need them. I am mocking the other Firebase properties required.
How would I ignore #addTrace when calling the function during test.
Related
https://pub.dev/documentation/firebase_messaging/latest/firebase_messaging/FirebaseMessaging/instance.html
static FirebaseMessaging get instance
{
return FirebaseMessaging._(app: Firebase.app());
}
instance word here does not have () after it, but it has {}.
Even while calling it we use: FirebaseMessaging.instance. No brackets.
Is this a function or something else?
There is 2 things to understand why you can call FirebaseMessaging.instance:
Getter
FirebaseMessaging get instance { /* ... */ }
First thing to understand is the concept of a getter defined by the keyword get. A getter is a method which does not take any arguments and which returns a value. In this case you have a getter named instance which returns an object of type FirebaseMessaging.
So a getter is technically a function which could also be written like this:
FirebaseMessaging getInstance() { /* ... */ }
But a getter is supposedly faster as it is dedicated to only retrieve values.
Static method
Now how can you have access to this getter/method without needing an instance of the FirebaseMessaging object ? Well, it is simply because of the static keyword used for the getter:
static FirebaseMessaging get instance { /* ... */ }
Any method or variable declared within a class with the static keyword is the same for every instance of this class. Basically a single copy of this method will be shared among all instances of the FirebaseMessaging class. It allocates memory only once at the class loading.
So by calling FirebaseMessaging.instance you are calling a static method.
I want to write an integration test using a real repository but also verify behavior of the repository
SomeService(IRepository r) calls r.QuerySomething()
And I've been trying to achieve this using Moq:
var mock = new Mock<IRepository >(() => new Repository());
mock.CallBase = true;
The trouble is that it never calls methods from Repository nor does it call it's constructor. The lambda over there is meant for getting ctor parameters (if type is a class) not for object initialization.
Q: How do I wrap new Repository() into a Mock<IIRepository> so I can verify calls?
NB: it works if the type give is a class but I cannot then use it for verifying since they implementatin is not virtual.
Alternatively is there some other nuget that can help me achieve this?
There is a technique that I use for testing brownfiled legacy code, it can probably help, in what you're trying to achieve. You can introduce a decorator into your tests project that wraps your original implementation, but also implements the IRepository interface.
class TestRepository : IRepostiory
{
public TestRepository(Repository next)
{
this.next = next;
}
}
Inside this class you can declare all the interface members as virtual.
class TestRepository : IRepostiory
{
public virtual IReadOnlyList<Client> GetByName(string name)
{
return this.next.GetByName(name);
}
}
Now you can use the TestRepository in place of your original implementation and also create a mock that verifies the calls to this class.
var repository = new Repository();
var sutMock = new Mock<TestRepository>(repository) { CallBase = true };
var sut = sutMock.Object;
sut.GetByName("John Doe");
sutMock.Verify(x => x.GetByName("John Doe"), Times.Once);
NB: The fact that you'd need a legacy code testing technique probably indicates to a code smell. I would recommend, as a first step, splitting the tests that assert the mock from those that assert the real implementation results (changes in the persistence layer).
I am trying to use the Firebase package with the below line of code.
I really want to know what this line of code actually does?
The official documentation didn't help me much. Can someone explain me, please?
You have to use it, in this way:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
https://flutter.dev/docs/resources/architectural-overview#architectural-layers
The above image is the architecture layers of Flutter, the WidgetFlutterBinding is used to interact with the Flutter engine. Firebase.initializeApp() needs to call native code to initialize Firebase, and since the plugin needs to use platform channels to call the native code, which is done asynchronously therefore you have to call ensureInitialized() to make sure that you have an instance of the WidgetsBinding.
From the docs:
Returns an instance of the WidgetsBinding, creating and initializing it if necessary. If one is created, it will be a WidgetsFlutterBinding. If one was previously initialized, then it will at least implement WidgetsBinding.
You only need to call this method if you need the binding to be initialized before calling runApp.
From the source code:
#override
Future<FirebaseAppPlatform> initializeApp(
{String name, FirebaseOptions options}) async {
if (name == defaultFirebaseAppName) {
throw noDefaultAppInitialization();
}
// Ensure that core has been initialized on the first usage of
// initializeApp
if (!isCoreInitialized) {
await _initializeCore();
}
// If no name is provided, attempt to get the default Firebase app instance.
// If no instance is available, the user has not set up Firebase correctly for
// their platform.
if (name == null) {
MethodChannelFirebaseApp defaultApp =
appInstances[defaultFirebaseAppName];
if (defaultApp == null) {
throw coreNotInitialized();
}
return appInstances[defaultFirebaseAppName];
}
assert(options != null,
"FirebaseOptions cannot be null when creating a secondary Firebase app.");
// Check whether the app has already been initialized
if (appInstances.containsKey(name)) {
throw duplicateApp(name);
}
_initializeFirebaseAppFromMap(await channel.invokeMapMethod(
'Firebase#initializeApp',
<String, dynamic>{'appName': name, 'options': options.asMap},
));
return appInstances[name];
}
The invokeMapMethod will invoke a method on the above channel with the specified arguments, which will then call the initializeApp() method in the native code,
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_core/firebase_core/android/src/main/java/io/flutter/plugins/firebase/core/FlutterFirebaseCorePlugin.java#L227
There are also different ways to initialize Firebase, which you can check here:
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase
In the other ways we do not call WidgetsFlutterBinding.ensureInitialized() since the runApp() function calls it internally:
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
https://github.com/flutter/flutter/blob/bbfbf1770c/packages/flutter/lib/src/widgets/binding.dart#L1012
A simple answer is that if Flutter needs to call native code before calling runApp
WidgetsFlutterBinding.ensureInitialized();
makes sure that you have an instance of the WidgetsBinding, which is required to use platform channels to call the native code.
You only need to call this method if you need the binding to be
initialized before calling runApp.
A simple answer, you need to use this line, if your main function uses async keyword because you use await statement inside it.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance(); // just an example
}
I'm trying to access chatting room Using firestore and coroutines.
fun getOwner() {
runBlocking {
var de = async(Dispatchers.IO) {
firestore.collection("Chat").document("cF7DrENgQ4noWjr3SxKX").get()
}
var result = de.await().result
}
But i get error like this :
E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.example.map_fetchuser_trest, PID: 19329
java.lang.IllegalStateException: Task is not yet complete
at com.google.android.gms.common.internal.Preconditions.checkState(Unknown Source:29)
at com.google.android.gms.tasks.zzu.zzb(Unknown Source:121)
at com.google.android.gms.tasks.zzu.getResult(Unknown Source:12)
at com.example.map_fetchuser_trest.model.Repository$getOwner$1.invokeSuspend(Repository.kt:53)
How can i get chat document? when i use origin api like below, I can access chat room document.
firestore.collection("Chat").document(
"cF7DrENgQ4noWjr3SxKX"
).get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val chatDTO = task.result?.toObject(Appointment::class.java)
}
}
Task is the thing one awaits on, but you wrapped it in another layer of async. Remove the async:
fun getOwner() {
runBlocking {
var de = firestore.collection("Chat").document("cF7DrENgQ4noWjr3SxKX").get()
var result = de.await().result
}
}
However, by using runBlocking() you have shot yourself in the foot and wrote blocking code that just formally uses an async API to no good effect.
To truly benefit from it, you must have a
suspend fun getOwner() = firestore
.collection("Chat")
.document("cF7DrENgQ4noWjr3SxKX")
.get()
.await()
.result
and launch a coroutine at the place you call it from:
launch {
val owner = getOwner()
// update the GUI
}
This assumes you're calling launch from an object that is a CoroutineScope.
val db = FirebaseFirestore.getInstance()
override suspend fun saveBinToDB(bin: Bin): Result<Unit> {
lateinit var result:Result<Unit>
db.collection("bins")
.add(bin)
.addOnSuccessListener { documentReference ->
Log.d(TAG, "DocumentSnapshot written with ID: ${documentReference.id}")
result = Result.Success(Unit)
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding document", e)
result = Result.Error(Exception())
}
.await()
return result
}
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.7"
The usage of runBlocking{..} in the first code snippet works as follows: the runBlocking function blocks to execute the parameter lambda code (and the lambda code will suspend inside). It gives less sense.
You may want to start a coroutine with launch{..} function instead and use withContext(Dispatchers.Main){..} to have the block executed in the UI thread, e.g. to show the fetched results. You may also implement CoroutineScope in your activity class.
The first step - you need to turn the Firebase API call into a suspending function. It could be done with suspendCoroutine{..} function (there are several more functions like suspendCancellableCoroutine{..} in the kotlinx.coroutines library.
There is an integration library with Google Play Services that provides support for Firebase
https://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-play-services
I struggled to get await() function. Check your build.gradle should have below dependencies -
def coroutines = '1.6.4'
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines"
Now instead of Complete/Failure Listener, use await() just like used in #Marko answer -
suspend fun getDataFromFireStore() = firestore
.collection("some key")
.document("some key")
.get()
.await()
.documents
We basically have a class that looks like this below that is using the Castle.DynamicProxy for Interception.
using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Castle.DynamicProxy;
namespace SaaS.Core.IoC
{
public abstract class AsyncInterceptor : IInterceptor
{
private readonly ILog _logger;
private readonly ConcurrentDictionary<Type, Func<Task, IInvocation, Task>> wrapperCreators =
new ConcurrentDictionary<Type, Func<Task, IInvocation, Task>>();
protected AsyncInterceptor(ILog logger)
{
_logger = logger;
}
void IInterceptor.Intercept(IInvocation invocation)
{
if (!typeof(Task).IsAssignableFrom(invocation.Method.ReturnType))
{
InterceptSync(invocation);
return;
}
try
{
CheckCurrentSyncronizationContext();
var method = invocation.Method;
if ((method != null) && typeof(Task).IsAssignableFrom(method.ReturnType))
{
var taskWrapper = GetWrapperCreator(method.ReturnType);
Task.Factory.StartNew(
async () => { await InterceptAsync(invocation, taskWrapper).ConfigureAwait(true); }
, // this will use current synchronization context
CancellationToken.None,
TaskCreationOptions.AttachedToParent,
TaskScheduler.FromCurrentSynchronizationContext()).Wait();
}
}
catch (Exception ex)
{
//this is not really burring the exception
//excepiton is going back in the invocation.ReturnValue which
//is a Task that failed. with the same excpetion
//as ex.
}
}
....
Initially this code was:
Task.Run(async () => { await InterceptAsync(invocation, taskWrapper)).Wait()
But we were losing HttpContext after any call to this, so we had to switch it to:
Task.Factory.StartNew
So we could pass in the TaskScheduler.FromCurrentSynchronizationContext()
All of this is bad because we are really just swapping one thread for another thread. I would really love to change the signature of
void IInterceptor.Intercept(IInvocation invocation)
to
async Task IInterceptor.Intercept(IInvocation invocation)
And get rid of the Task.Run or Task.Factory and just make it:
await InterceptAsync(invocation, taskWrapper);
The problem is Castle.DynamicProxy IInterecptor won't allow this. I really want do an await in the Intercept. I could do .Result but then what is the point of the async call I am calling? Without being able to do the await I lose out of the benefit of it being able to yield this threads execution. I am not stuck with Castle Windsor for their DynamicProxy so I am looking for another way to do this. We have looked into Unity, but I don't want to replace our entire AutoFac implementation.
Any help would be appreciated.
All of this is bad because we are really just swapping one thread for another thread.
True. Also because the StartNew version isn't actually waiting for the method to complete; it will only wait until the first await. But if you add an Unwrap() to make it wait for the complete method, then I strongly suspect you'll end up with a deadlock.
The problem is Castle.DynamicProxy IInterecptor won't allow this.
IInterceptor does have a design limitation that it must proceed synchronously. So this limits your interception capabilities: you can inject synchronous code before or after the asynchronous method, and asynchronous code after the asynchronous method. There's no way to inject asynchronous code before the asynchronous method. It's just a limitation of DynamicProxy, one that would be extremely painful to correct (as in, break all existing user code).
To do the kinds of injection that is supported, you have to change your thinking a bit. One of the valid mental models of async is that a Task returned from a method represents the execution of that method. So, to append code to that method, you would call the method directly and then replace the task return value with an augmented one.
So, something like this (for return types of Task):
protected abstract void PreIntercept(); // must be sync
protected abstract Task PostInterceptAsync(); // may be sync or async
// This method will complete when PostInterceptAsync completes.
private async Task InterceptAsync(Task originalTask)
{
// Asynchronously wait for the original task to complete
await originalTask;
// Asynchronous post-execution
await PostInterceptAsync();
}
public void Intercept(IInvocation invocation)
{
// Run the pre-interception code.
PreIntercept();
// *Start* the intercepted asynchronous method.
invocation.Proceed();
// Replace the return value so that it only completes when the post-interception code is complete.
invocation.ReturnValue = InterceptAsync((Task)invocation.ReturnValue);
}
Note that the PreIntercept, the intercepted method, and PostInterceptAsync are all run in the original (ASP.NET) context.
P.S. A quick Google search for async DynamicProxy resulted in this. I don't have any idea how stable it is, though.