I generally store away all the command line options to a different class, say, CliArguments. This avoids the noise in the main class. This is what I have with picocli:
public final class MyApp {
private static final CliArguments cliArgs = new CliArguments();
private MyApp() {}
public static void main (String[] args) {
if (parseArgs (args)) {
new MyApp().execute();
}
}
/* want to avoid this boiler plate */
private static boolean parseArgs(String[] args) {
CommandLine cmd = new CommandLine ( cliArgs );
try {
cmd.parseArgs( args );
if (cmd.isUsageHelpRequested()) {
cmd.usage( cmd.getOut() );
return false;
}
else if ( cmd.isVersionHelpRequested() ) {
cmd.printVersionHelp (cmd.getOut());
return false;
}
logger.info("{}", cliArgs);
return true;
}
catch ( ParameterException ex ) {
logger.error ("Failure to parse : {}", ex);
return false;
}
}
private void execute() {
// execution logic
}
}
How do I avoid the boiler plate method, pargeArgs(String[])? The CliArguments class, technically, should not implement a Callable or Runnable. I can make MyApp be a Callable or Runnable. but to CommandLine, new MyApp() is not a command, new CliArguments() is.
If I want to do something like this:
final int exitCode = new CommandLine(new MyApp()).execute(args);
if (0 != exitCode) {
logger.error("Failed to parse");
System.exit(exitCode);
}
how do I push off all the #Option specification to a different class, CliArguments while still having the execution control in MyApp?
I am sure I am missing something straight forward.
The simplest way to achieve this is by making CliArguments a mixin in MyApp. We can then put the business logic in MyApp, and make it a Runnable or Callable so we can bootstrap the application with new CommandLine(new MyApp()).execute(args).
For example:
#Command(mixinStandardHelpOptions = true, version = "1.0.0")
public class CliArgs {
#Option(names = "-x") boolean x;
#Option(names = "-y") boolean y;
}
#Command(name = "myapp", description = "...")
public class MyApp implements Runnable {
// options defined in the mixin are added to this command
// also, #Command attributes from the mixin are applied to this command
#Mixin
CliArgs cliArgs;
public void run() {
System.out.printf("-x=%s%n", cliArgs.x);
System.out.printf("-y=%s%n", cliArgs.y);
}
public void main(String... args) {
System.exit(new CommandLine(new MyApp()).execute(args));
}
}
The options defined in the CliArgs mixin become part of the MyApp mixee.
Also, any #Command attributes defined in CliArgs become part of the MyApp command.
You can now run:
java MyApp -x
and this will print
-x=true
-y=false
Since the mixin has #Command(mixinStandardHelpOptions = true), the MyApp command also has --help and --version options that work as you would expect.
Related
There is a quite simple case I would like to implement:
I have a base and DLT topics:
MessageBus:
Topic: my_topic
DltTopic: my_dlt_topic
Broker: event-serv:9092
So, those topics are already predefined, I don't need to create them automatically.
The only I need to handle broken messages automatically without retries, because they don't make any sense, so I have something like this:
#KafkaListener(topics = ["#{config.messageBus.topic}"], groupId = "group_id")
#RetryableTopic(
dltStrategy = DltStrategy.FAIL_ON_ERROR,
autoCreateTopics = "false",
attempts = "1"
)
#Throws(IOException::class)
fun consume(rawMessage: String?) {
...
}
#DltHandler
fun processMessage(rawMessage: String?) {
kafkaTemplate.send(config.messageBus.dltTopic, rawMessage)
}
That of course doesn't work properly.
I also tried to specify a kafkaTemplate
#Bean
fun kafkaTemplate(
config: Config,
producerFactory: ProducerFactory<String, String>
): KafkaTemplate<String, String> {
val template = KafkaTemplate(producerFactory)
template.defaultTopic = config.messageBus.dltTopic
return template
}
however, that does not change the situation.
In the end, I believe there is an obvious solution, so I please give me a hint about it.
See the documenation.
#SpringBootApplication
public class So69317126Application {
public static void main(String[] args) {
SpringApplication.run(So69317126Application.class, args);
}
#RetryableTopic(attempts = "1", autoCreateTopics = "false", dltStrategy = DltStrategy.FAIL_ON_ERROR)
#KafkaListener(id = "so69317126", topics = "so69317126")
void listen(String in) {
System.out.println(in);
throw new RuntimeException();
}
#DltHandler
void handler(String in) {
System.out.println("DLT: " + in);
}
#Bean
RetryTopicNamesProviderFactory namer() {
return new RetryTopicNamesProviderFactory() {
#Override
public RetryTopicNamesProvider createRetryTopicNamesProvider(Properties properties) {
if (properties.isMainEndpoint()) {
return new SuffixingRetryTopicNamesProviderFactory.SuffixingRetryTopicNamesProvider(properties) {
#Override
public String getTopicName(String topic) {
return "so69317126";
}
};
}
else if(properties.isDltTopic()) {
return new SuffixingRetryTopicNamesProviderFactory.SuffixingRetryTopicNamesProvider(properties) {
#Override
public String getTopicName(String topic) {
return "so69317126.DLT";
}
};
}
else {
throw new IllegalStateException("Shouldn't get here - attempts is only 1");
}
}
};
}
}
so69317126: partitions assigned: [so69317126-0]
so69317126-dlt: partitions assigned: [so69317126.DLT-0]
foo
DLT: foo
This is a Kafka server configuration so you must set it on the server. The relevant property is:
auto.create.topics.enable (true by default)
I have a problem with mocking cause it keep calling the original function. This is my demo code
First file is interface that contains the function that I want to mock.
public interface IDemoReplace
{
int FunctionToBeReplaced();
}
Second file is a class that actually has the implementation for the function
public class DemoReplace : IDemoReplace
{
public int FunctionToBeReplaced()
{
//this function contains sql query in my real project
return 1;
}
}
Third file is a class that I want to test
public class ClassToBeTested
{
public int TestThisFunction()
{
IDemoReplace replace = new DemoReplace();
var temp = replace.FunctionToBeReplaced();
return temp;
}
}
Last file is the test class
public class TestClass
{
[Fact]
public void TryTest()
{
using (var mock = AutoMock.GetLoose()) {
//Arrange
mock.Mock<IDemoReplace>()
.Setup(x => x.FunctionToBeReplaced())
.Returns(returnTwo());
var classToBeTested = mock.Create<ClassToBeTested>();
var expected = 2;
//Act
var actual = classToBeTested.TestThisFunction();
//Assert
Assert.Equal(expected, actual);
}
}
public int returnTwo() {
return 2;
}
}
This test will be failed with expected is 2 and actual is 1. When I tried to debug it doesn't call returnTwo but call the original function instead.
I am new to unit testing so what did I miss? Please be considered that the code above is only a demo of what is happened in my actual project. FunctionToBeReplaced is actually a function that execute and return record from database so I want to mock that function.
Thanks :)
This is a design issue. The subject under test is tight coupled to implementation concerns that make it difficult to isolation the subject so that it can be unit tested.
It (subject) is manually creating its dependency
IDemoReplace replace = new DemoReplace();
Ideally you want to explicitly inject dependencies. Those dependencies should also be abstractions and not concretions.
public class ClassToBeTested {
private readonly IDemoReplace dependency;
public ClassToBeTested(IDemoReplace dependency) {
this.dependency = dependency;
}
public int TestThisFunction() { ;
var temp = dependency.FunctionToBeReplaced();
return temp;
}
}
At run time, the implementation (or mock) can be injected, either purely, or via a container.
The test in the original example shown should now behave as expected.
public class TestClass {
[Fact]
public void TryTest() {
using (var mock = AutoMock.GetLoose()) {
//Arrange
var expected = returnTwo();
mock.Mock<IDemoReplace>()
.Setup(x => x.FunctionToBeReplaced())
.Returns(expected);
var classToBeTested = mock.Create<ClassToBeTested>();
//Act
var actual = classToBeTested.TestThisFunction();
//Assert
Assert.Equal(expected, actual);
}
}
public int returnTwo() {
return 2;
}
}
I am working on a POC for a console application and I am struggling to retrieve the command line values from the configuration after using AddCommandLine in the set up.
csproj
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
Program class
public static class Program
{
public static async Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.RollingFile("Logs//log.txt")
.CreateLogger();
await CreateHostBuilder(args)
.Build()
.RunAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("settings.json", true, true);
config.AddCommandLine(args);
})
.ConfigureServices((hostcontext, services) =>
{
services.AddHostedService<ConsoleApp>();
});
}
ConsoleApp class
public class ConsoleApp : IHostedService
{
private readonly IConfiguration config;
private readonly ILogger<ConsoleApp> log;
public ConsoleApp(IConfiguration configuration, ILogger<ConsoleApp> logger)
{
config = configuration;
log = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
var t = config.GetSection("Args");
Parser.Default.ParseArguments<DeleteOptions>(t)
.WithParsed<DeleteOptions>()
.WithNotParsed();
foreach (var c in config.AsEnumerable())
{
log.LogInformation($"{c.Key, -15}:{c.Value}");
}
log.LogInformation($"Completing Start Task");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
log.LogInformation($"Complete End Task");
return Task.CompletedTask;
}
}
The Parser section before the foreach loop does not compile and the output from the loop does not print out any of the arguments I have added.
I am aware of the general advice that var someValue = Configuration.GetValue<int>("MySetting:SomeValue"); where the argument is --MySetting=SomeValue is the recommended way to retrieve cmd line values.
The values I am using as parameters are delete -e CI -t depchpolestar -l de-DE and when I look at my config object I see
which is why I think the line var t = config.GetSection("Args"); should retrieve the args array. I have also tried var t = config.GetValue<string[]>("Args"); but neither seems to work. It appears to me that index 4 of the configuration object is a string array keyed by "Args"
How do I retrieve the string array so I can pass it into CommandLineParser's ParseArguments method?
[Edit] One Solution:
I can now get the args passed through but it is not a particularly nice approach; If I construct the argument as --delete "-e CI -t depchpolestar -l de-DE" instead of delete -e CI -t depchpolestar -l de-DE and adding the following code to the ConsoleApp class:
var args = config.GetValue<string>("delete");
string[] arguments = null;
if(!string.IsNullOrEmpty(args))
{
var tempArgs = args.Split(" ");
arguments = new string[tempArgs.Length + 1];
arguments[0] = "delete";
for(int i = 0; i < tempArgs.Length; ++i)
{
arguments[i + 1] = tempArgs[i];
}
}
Parser.Default.ParseArguments<DeleteOptions>(arguments)
.WithParsed<DeleteOptions>(async c => await c.Dowork())
.WithNotParsed(HandleParseError);
execution hits the DoWork method. Good but DeleteOptions.cs defines a Verb and the intention is to add more commands. So more work to do but going the right way.
[Edit] I have also realised that I do not need to add the AddCommandLine() call as they are added by default.
ok it seemed that I over complicated this and ended up with this:
public static class Program
{
public static async Task Main(string[] args)
{
var builtHost = CreateHostBuilder(args).Build();
var console = builtHost.Services.GetService<ConsoleApp>();
await console.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("settings.json", true, true);
config.AddCommandLine(args);
})
.ConfigureServices((hostcontext, services) =>
{
services.AddTransient<ConsoleApp>();
});
}
and this as the run method in ConsoleApp:
public Task Run()
{
while (true)
{
var input = ReadFromConsole();
if (string.IsNullOrWhiteSpace(input))
{
continue;
}
else if (input.ToLower().Equals("exit"))
{
break;
}
else
{
Parser.Default.ParseArguments<DeleteOptions, ConcatOptions, DownloadOptions, ReportOptions>(input.Split(" "))
.WithParsed<DeleteOptions>(async options => await options.DoWork())
.WithParsed<ConcatOptions>(async options => await options.DoWork())
.WithParsed<DownloadOptions>(async options => await options.DoWork())
.WithParsed<ReportOptions>(async options => await options.DoWork())
.WithNotParsed(HandleParseError);
}
}
return Task.CompletedTask;
}
This works fine for allowing me to use it as an interactive console app. I do have a problem with the DI though. I have created an OptionsBase class which set up logging and I have done it this way as trying to add a parameter to any of the Options classes fails stating unable to find the parameterless constructor. So I am assuming that CommandLine requires default constructors to work. Gett ing a logger the way I have gives me multiple log files so I need to fix that.
Hello I am trying to create my first game in unity which I wanna be network aware but I encoured a problem with network prefabs spawning. Here's my code:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class Builder : NetworkBehaviour {
public GameObject preview;
public Transform currentPreview;
bool isPreviewing = false;
GameObject buildingPreview;
private NetworkIdentity networkId;
// Use this for initialization
void Start ()
{
networkId = GetComponent<NetworkIdentity>();
}
// Update is called once per frame
void ViewPreview()
{
buildingPreview = Instantiate(preview, transform.position, transform.rotation) as GameObject;
currentPreview = buildingPreview.transform;
isPreviewing = true;
}
void Update ()
{
CmdBuild();
}
void CmdBuild()
{
if (networkId.isLocalPlayer)
{
}
else
{ return; }
if (Input.GetKeyDown(KeyCode.E))
{
if (!isPreviewing)
ViewPreview();
else
{
Destroy(buildingPreview);
isPreviewing = false;
}
}
if (isPreviewing)
{
Preview();
}
}
[Command]
void CmdSpawnBuilding()
{
GameObject buildingPlaced = Instantiate(preview, currentPreview.position, currentPreview.rotation) as GameObject;
NetworkServer.Spawn(buildingPlaced);
}
void Preview()
{
currentPreview.position = transform.position + transform.forward * 3f;
currentPreview.rotation = transform.rotation;
if (Input.GetButtonDown("Fire1"))
{
CmdSpawnBuilding();
isPreviewing = false;
}
}
}
Compiler says there's no problem but in unity I've got such error: "UNetWeaver error: Script Builder uses [Command] CmdSpawnBuilding but is not a NetworkBehaviour. UnityEngine.Debug:LogError(Object)" My code runs perfetly good without "[Command]" line despites it's not network aware. Also, I know it's a bit messed up but I was trying to figure it out what's wrong and so yeah, messed code a bit.
Your class needs to inherit from NetworkBehaviour, like this:
public class Builder : NetworkBehaviour
I'm trying to write this simple test:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var postProcessingAction = fixture.Freeze<Mock<IPostProcessingAction>>();
var postProcessor = fixture.Freeze<PostProcessor>();
postProcessor.Process("", "");
postProcessingAction.Verify(action => action.Do());
The Verify check fails.
The code for postProcessor.Process is
public void Process(string resultFilePath, string jobId)
{
IPostProcessingAction postProcessingAction =
postProcessingActionReader
.CreatePostProcessingActionFromJobResultXml(resultFilePath);
postProcessingAction.Do();
}
postProcessingActionReader is an interface field initialized through the constructor.
I'm expecting the test to pass but it fails, it turns out the instance of IPostProessingAction returned from the CreatePostProcessingActionFromJobResultXml method is not the same instance as returned from fixture.Freeze<>.
My expectation was that after freezing this Mock object it would inject the underlying mock of the IPostProcessingAction interface in every place its required as well as make all mock methods returning IPostProcessingAction return this same object.
Is my expectation about the return value of the mock methods incorrect?
Is there a way to change this behavior so that mock methods return the same frozen instance?
You need to Freeze the IPostProcessingActionReader component.
The following test will pass:
[Fact]
public void Test()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var postProcessingActionMock = new Mock<IPostProcessingAction>();
var postProcessingActionReaderMock = fixture
.Freeze<Mock<IPostProcessingActionReader>>();
postProcessingActionReaderMock
.Setup(x => x.CreatePostProcessingActionFromJobResultXml(
It.IsAny<string>()))
.Returns(postProcessingActionMock.Object);
var postProcessor = fixture.CreateAnonymous<PostProcessor>();
postProcessor.Process("", "");
postProcessingActionMock.Verify(action => action.Do());
}
Assuming that the types are defined as:
public interface IPostProcessingAction
{
void Do();
}
public class PostProcessor
{
private readonly IPostProcessingActionReader actionReader;
public PostProcessor(IPostProcessingActionReader actionReader)
{
if (actionReader == null)
throw new ArgumentNullException("actionReader");
this.actionReader = actionReader;
}
public void Process(string resultFilePath, string jobId)
{
IPostProcessingAction postProcessingAction = this.actionReader
.CreatePostProcessingActionFromJobResultXml(resultFilePath);
postProcessingAction.Do();
}
}
public interface IPostProcessingActionReader
{
IPostProcessingAction CreatePostProcessingActionFromJobResultXml(
string resultFilePath);
}
In case you use AutoFixture declaratively with the xUnit.net extension the test could be simplified even further:
[Theory, AutoMoqData]
public void Test(
[Frozen]Mock<IPostProcessingActionReader> readerMock,
Mock<IPostProcessingAction> postProcessingActionMock,
PostProcessor postProcessor)
{
readerMock
.Setup(x => x.CreatePostProcessingActionFromJobResultXml(
It.IsAny<string>()))
.Returns(postProcessingActionMock.Object);
postProcessor.Process("", "");
postProcessingActionMock.Verify(action => action.Do());
}
The AutoMoqDataAttribute is defined as:
internal class AutoMoqDataAttribute : AutoDataAttribute
{
internal AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
As of 3.20.0, you can use AutoConfiguredMoqCustomization. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.
In other words, it will auto-configure your postProcessingActionReader to return the frozen postProcessingAction.
Just change this:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
to this:
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());