I'm trying to set an initial value to the public ReactiveProperty<string> ConnectionStatus.
public ViewModelConstructor()
{
ConnectionStatus = Observable
.Interval(RefreshInterval)
.Select(x => Observable.FromAsync(() => networkDiscovererService.CanDiscoverAsync("192.168.1.1", RequestTimeout)))
.Concat()
.Select(isConnected => isConnected ? $"connected" : $"not connected")
.ToReactiveProperty();
}
Even if I'm trying to instantiate it like this
public ReactiveProperty<string> ConnectionStatus { get; } =
new ReactiveProperty<string>("Checking connectivity...");
It's still empty until the observable returns something.
Any ideas? I'm using this library.
To get initial value on subscribe (like behaviorSubject, or Replay(1)) using ReactiveProperty ctor:
[Test]
public void ShouldReturnAValuOnSubscribe()
{
var testScheduler = new TestScheduler();
var testableObserver = testScheduler.CreateObserver<int>();
var reactiveProperty = new ReactiveProperty<int>(30);
reactiveProperty.Subscribe(testableObserver);
Assert.AreEqual(30, testableObserver.Messages.Single().Value.Value);
}
To get initial value on subscribe (like behaviorSubject, or Replay(1)) using .ToReactiveProperty():
[Test]
public void ShouldReturnAValuOnToReactiveProperty()
{
var testScheduler = new TestScheduler();
var testableObserver = testScheduler.CreateObserver<int>();
var reactiveProperty = Observable.Never<int>().ToReactiveProperty(40);
reactiveProperty.Subscribe(testableObserver);
Assert.AreEqual(40, testableObserver.Messages.Single().Value.Value);
}
NOT to get initial value on subscribe - change ReactivePropertyMode:
[Test]
public void ShouldNotReturnAnInitialValue_WhenModeIsNone_AndOnSubscribe()
{
var testScheduler = new TestScheduler();
var testableObserver = testScheduler.CreateObserver<int>();
var reactiveProperty = new ReactiveProperty<int>(30, ReactivePropertyMode.None);
reactiveProperty.Subscribe(testableObserver);
Assert.IsEmpty(testableObserver.Messages);
}
Basically, what you're looking for is initial value and ReactivePropertyMode.RaiseLatestValueOnSubscribe flag.
In the first case you forgot to provider ToReactiveProperty() with initial value (e.g. ToReactiveProperty(30))
It should've worked for you in the second case - the mode is set to ReactivePropertyMode.RaiseLatestValueOnSubscribe by default (check ShouldReturnAValuOnSubscribe). Try to set the mode explicitly (like in ShouldNotReturnAnInitialValue_WhenModeIsNone_AndOnSubscribe).
I used ReactiveProperty 3.6.0.
btw, It's not a very good idea to test a connection based on timer :)
Related
I am trying to write a unit test that verifies that adding a new property to an Avro schema is backwards compatible.
First I took the Avro generated .cs model and saved it as MyModelOld.cs and renamed the class inside to MyModelOld.
Then I re-ran Avro gen against the avsc file with the new property.
What I'm trying to do is this:
var schemaRegistry = -> something that doesn't require a running docker image <-;
var deserializerOld = new AvroDeserializer<MyModelOld>(schemaRegistry);
var serializerNew = new AvroSerializer<MyModel>(schemaRegistry);
var myModel = new MyModel() {...};
var myModelBytes = await serializerNew.SerializeAsync(myModel, new());
var myModelOld = await deserializerOld.DeserializeAsync(myModelBytes, false, new());
// Check properties...
Then I was going to go the opposite direction and check that the new property uses the specified default value.
The problem I'm having is what to use for the schema registry. I don't want to have a docker image running for these tests because I don't think it shouldn't be necessary.
I've tried a mock of ISchemaRegistry, but it appears to need a fully functional class in order for serialize/deserialize to work.
I could probably walk through the logic for CachedSchemaRegistryClient and try to munge it to work, but before I do so I'd like to find out if someone knows of an ISchemaRegistry implementaion that would work for my use case.
Has anyone tried to write tests to validate backwards compatibility of Avro schema updates?
If so, how did you go about doing so?
Thanks.
I ended up doing it this way:
private ISchemaRegistryClient NewTestRegistry(string topic)
{
// Code to mock SchemaRegistry taken from:
// https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/test/Confluent.SchemaRegistry.Serdes.UnitTests/SerializeDeserialize.cs
Dictionary<string, int> store = new Dictionary<string, int>();
var schemaRegistryMock = new Mock<ISchemaRegistryClient>();
#pragma warning disable CS0618 // Type or member is obsolete
schemaRegistryMock.Setup(x => x.ConstructValueSubjectName(topic, It.IsAny<string>()))
.Returns($"{topic}-value");
schemaRegistryMock.Setup(x => x.RegisterSchemaAsync($"{topic}-value", It.IsAny<string>(), It.IsAny<bool>()))
.ReturnsAsync((string topic, string schema, bool normalize) =>
store.TryGetValue(schema, out int id) ? id : store[schema] = store.Count + 1
);
#pragma warning restore CS0618 // Type or member is obsolete
schemaRegistryMock.Setup(x => x.GetSchemaAsync(It.IsAny<int>(), It.IsAny<string>()))
.ReturnsAsync((int id, string format) =>
new Schema(store.Where(x => x.Value == id).First().Key, null, SchemaType.Avro)
);
return schemaRegistryMock.Object;
}
[TestMethod]
public async Task BackwardsCompatible()
{
var topic = "MyCoolTopic";
var schemaRegistry = NewTestRegistry(topic);
var context = new SerializationContext(MessageComponentType.Value, topic);
var deserializerOld = new AvroDeserializer<MyModelOld>(schemaRegistry);
var serializerNew = new AvroSerializer<MyModel>(schemaRegistry);
var myModel = new MyModel() { /* Set properties */};
var myModelBytes = await serializerNew.SerializeAsync(myModel, context);
var myModelOld = await deserializerOld.DeserializeAsync(myModelBytes, false, context);
// Check properties...
}
[TestMethod]
public async Task ForwardsCompatible()
{
// Similar to the above test.
}
If you want to test schemas, you don't need Kafka-related serializers; just use raw Avro C# library.
Alternatively, look at the existing tests
var config = new SchemaRegistryConfig { Url = "irrelevanthost:8081" };
var src = new CachedSchemaRegistryClient(config);
Assert...(src... );
I'am trying to test persistence actor, but behavior is wierd.
My tested actor:
public class PredictionManager : ReceivePersistentActor
{
public override string PersistenceId => _persistanceId;
public PredictionManager(string persistenceId)
{
_persistanceId = persistenceId;
Command<AddPredictionRequest>(OnPrediction);
Recover<SnapshotOffer>(x => OnRecover((PredictionManagerState)x.Snapshot), x => x.Snapshot is PredictionManagerState);
}
private void OnPrediction(AddPredictionRequest request)
{
/* some code */
_state.Add(request);
SaveSnapshot(_state);
}
private void OnRecover(PredictionManagerState state)
{
foreach(var request in state.RequestMap)
{
OnPrediction(request.Value);
}
}
}
My state save all messages and deletes them after manager actor recieve some message. When I try to debug my test, Recover function called first and after this called OnPrediction. My question is - how it's possible? If data stores in momory, why it have SnapshotOffer? Also I have tried to generate new percistenceId from Guid.NewGuid() but it doesn't work.
public void AddPrediction_PassToChild_CreateNewManager_PassToChild()
{
var sender = CreateTestProbe(Sys);
var persistanceId = "AddPrediction_PassToChild_CreateNewManager_PassToChild";
var props = Props.Create(() => new PredictionManager(Mock.Of<IEventBus>(), persistanceId));
var predictionManager = ActorOf(props);
var message = new PredictionManager.AddPredictionRequest(Props.Create(() => new ChildTestActor(sender.Ref)),
new StartPrediction<IPredictionParameter>("a", 1, "a", new Param() ));
//Act
predictionManager.Tell(message, sender);
sender.ExpectMsg<string>(x => x == "ok", TimeSpan.FromSeconds(15));
Sys.Stop(predictionManager);
predictionManager = Sys.ActorOf(props);
sender.ExpectMsg<string>(x => x == "ok", TimeSpan.FromSeconds(15));
Sys.Stop(predictionManager);
}
I found out that default storage for snapshots is LocalStorage not MemoryStorage. So it stores snapshots in files, and this is why it has SnapshotOffer after app restart. But I still can't get why Guid.NewGuid() as persistanceId is not working.
I am trying to test a function that uses IDistrubtedMemory cache, I've configured the cache mock object's Get and Set and the Get function seems to be functioning, but when I set a new memory object, it never gets returned. Below is the test
-- Test code
[Fact]
public async void Can_AddToMonitoring()
{
var cacheKey = "Simulator";
var tList = new List<string>();
var tNumber = Guid.NewGuid().ToString().Substring(0, 6);
// Setup - Add mock objects that are needed
var mockLogger = new Mock<ILogger<TSimulatorService>>();
var mockCache = new Mock<IDistributedCache>();
mockCache.Setup(cacheMoc => cacheMoc.Get(It.IsAny<string>()))
.Returns(Mock.Of<byte[]>);
mockCache.Setup(cacheMoc => cacheMoc.Set(It.IsAny<string>(), It.IsAny<byte[]>(), null));
var mockEventBus = new Mock<IEventBus>();
var tSimulationService = new TSimulatorService(mockLogger.Object, mockEventBus.Object, mockCache.Object);
await tSimulationService.AddToMonitoring(tNumber);
// Assert - Verify the MemoryCache contains the tag we sent over
var testTag = await tSimulationService.GetTsForPublish();
var tSimulations = testTag as TSimulation[] ?? testT.ToArray();
tSimulations.ShouldNotBeEmpty();
tSimulations.ShouldContain( t => t.TNumber.Equals(tNumber));
}
This is the method I am attempting to test
public async Task AddToMonitoring(string tNumber)
{
var cacheList = await GetMonitoredTListFromCache();
var tList = cacheList.ToList();
if (!tagList.Contains(tNumber))
tList.Add(tNumber);
await _cache.SetStringAsync(tListCacheKey, JsonConvert.SerializeObject(tList));
}
Everything appears to work until I get to the Assert part of the test, when I attempt to pull the object I set, all I get is a null return and i am not entirely sure of why?
I have this piece of code and want to test that opts.Items["foo"] is set correctly.
public Result DoStuff(MyInput myObj)
{
var mapped = _mapper.Map<Result>(myObj,
opts =>
{
opts.Items["foo"] = "bar";
});
return mapped;
}
And my test looks like this
public void MapperShouldBeCalledWithCorrectOperationItems()
{
// Arrange
var optObj = Substitute.For<IMappingOperationOptions>();
Action<IMappingOperationOptions> argumentUsed = null;
_mapper.Received().Map<Result>(result, Arg.Do<Action<IMappingOperationOptions>>(arg => argumentUsed = arg));
// Act
_uut.DoStuff(new MyInput());
argumentUsed.Invoke(optObj);
// Assert
optObj.Items["foo"].Should().Be("bar");
}
Now this doesn't work and I'm not even sure I'm on the right path :(
I don't think I can inspect the lambda so I instead have to check that IMappingOperationOptions have Items["foo"] set.
Any suggestions?
I figured it out!
public void MapperShouldBeCalledWithCorrectOperationItems()
{
// Arrange
var optObj = Substitute.For<IMappingOperationOptions>();
Action<IMappingOperationOptions> argumentUsed = null;
_mapper
.Map<Result>(Arg.Any<Result>,
Arg.Do<Action<IMappingOperationOptions>>(arg => argumentUsed = arg));
// Act
_uut.DoStuff(new MyInput());
argumentUsed.Invoke(optObj);
// Assert
optObj.Items["foo"].Should().Be("bar");
}
I made a sandbox example that generates the exception:
public class Account
{
public string Status { get; set; }
}
[Fact]
public void MyTest()
{
dynamic scope = new ExpandoObject();
scope.Account = new Account();
scope.Account.Status = "test0";
// Can we get the value of the property?
var result = new CompiledExpression("Account.Status").ScopeCompile().DynamicInvoke((object)scope);
Assert.Same("test0", result); // Yes we can!
// Can we set the value of the property?
new CompiledExpression("Account.Status = 'test1'").ScopeCompile().DynamicInvoke((object)scope); // This throws an exception
Assert.Same("test1", ((string)(scope.Account.Status)));
}
If it's not clear I have a scope ExpandoObject that has properties that are not dynamic - and I'm trying to set a property (Status) of a property (Account) through parsing an expression. What am I doing wrong/why am I getting an exception setting when getting works fine?
I'm using this library:
https://csharpeval.codeplex.com/
> Install-Package ExpressionEvaluator
Alternatively, if there's a better library to do this (I've already given up on Simpro) then let me know and I can use it, instead.
(I'm using xunit as my tester, but I don't think that matters - hence [Fact] and not MsTest attributes.)
Per the documentation for CompiledExpression you need to use single quotes for string literals. So, the setter should be:
new CompiledExpression("Account.Status = 'test1'").ScopeCompile()
.DynamicInvoke((object)scope);
EDIT:
I've got this working:
var exp = new CompiledExpression("Status = 'test1'").ScopeCompile<Account>();
exp(scope.Account);
This also works:
var x = new CompiledExpression("Status = 'test2'").ScopeCompile<Account>();
var y = new CompiledExpression("Account").ScopeCompile();
x(y(scope));