Unit test LINQ to Xml method - unit-testing

How can I unit test an Xml file updater method?
public static void AllowComp(string Name)
{
var xml = XDocument.Load(XmlPath);
var comp = xml.Descendants("components").Single(c => c.Attribute("key").Value == Name);
comp.Attribute("allow").Value = "yes";
xml.Save(XmlPath);
}
Thank you

I would remove the XDocument.Load(xmlPath), and the save method to its own interface. For example IXmlComputation. Now you can write couple of tests.
a. Stub out the Load method and return a fake xml content. Unit Test the condition
var comp = xml.Descendants("components").Single(c => c.Attribute("key").Value == Name);
comp.Attribute("allow").Value = "yes";
b. Ensure the .Save(XmlPath); is called. Create a mock of IXmlComputation and verify the .Save method is called.
public interface IXmlComputation
{
public XDcoument Load(string xmlPath);
public void Save(string xmlPath);
}

Related

How to write unit test for spring cloud stream function based method?

When I try to test a spring cloud stream function based method, it always happens NullPointerException about InputDestination.
I have two questions:
It's hard for me to know how to write UT from the official doc. official test doc
Besides, how to write integration Test if test file has some dependencies. It seems create a new context and always has NoSuchBeanDefination error.
I have tried as flow, but the context can not find some dependency beans.
#Test
public void sampleTest() {
try (ConfigurableApplicationContext context = new SpringApplicationBuilder(
TestChannelBinderConfiguration.getCompleteConfiguration(
MyTestConfiguration.class))
.run("--spring.cloud.function.definition=uppercase")) {
InputDestination source = context.getBean(InputDestination.class);
OutputDestination target = context.getBean(OutputDestination.class);
source.send(new GenericMessage<byte[]>("hello".getBytes()));
assertThat(target.receive().getPayload()).isEqualTo("HELLO".getBytes());
}
}
So I just want to write UT, but still have NPE.
Here is my code.
#Bean
public Function<Message<List<DemoBean>>, Message<DemoBean>> findFirstBean( ){
return message -> {
List<DemoBean> demoBeans = message.getPayload();
return MessageBuilder.withPayload(demoBeans.get( 0 )).build();
};
}
Here is my test.
#SpringBootTest
#ActiveProfiles(profiles = "local")
#Import({ TestChannelBinderConfiguration.class})
class FunctionDemoTest {
#Autowired
private InputDestination inputDestination;
#Autowired
private OutputDestination outputDestination;
private FunctionDemo functionDemo;
// some dependency need to mock
private DemoService demoService;
#BeforeEach
void setUp() {
demoService = Mockito.mock( DemoService.class );
functionDemo = new FunctionDemo( demoService);
}
#Test
public void findFirstBeanTest() {
DemoBean demoBean = new DemoBean();
demoBean.setName("Howard");
demoBean.setAge( 1 );
DemoBean demoBean1 = new DemoBean();
demoBean1.setName("Frank");
demoBean1.setAge( 2 );
List<DemoBean> demoBeanList = new ArrayList<>();
demoBeanList.add( demoBean );
demoBeanList.add( demoBean1 );
Message<List<DemoBean>> inputMessage = MessageBuilder.withPayload(demoBeanList).build();
inputDestination.send(inputMessage,"findFirstBean-in-0");
Assertions.assertNotNull( outputDestination.receive( 10000, "findFirstBean-out-0") );
}
}
Here is error:
java.lang.NullPointerException: while trying to invoke the method org.springframework.messaging.SubscribableChannel.send(org.springframework.messaging.Message) of a null object returned from org.springframework.cloud.stream.binder.test.InputDestination.getChannelByName(java.lang.String)
at org.springframework.cloud.stream.binder.test.InputDestination.send(InputDestination.java:89)
at com.successfactors.caf.listener.FunctionDemoTest.raePdrResultProcessor(FunctionDemoTest.java:82)
Well, I know the root cause of NPE.
Message<byte[]> receive(long timeout, String bindingName)
It seems should be destinationName instead of bindingName in source code.
Any other answers would be appreciated.

Junit error - No value present or no such element

testclass.java
#Test
public void testgetDictionaryValueListById() {
DictionaryValue dictionaryValue = new DictionaryValue();
dictionaryValue.setId(1);
dictionaryValue.setValueName("Test Dictionary Value");
dictionaryValue.setValueKey("12345678");
dictionaryValue.setStatus("Active");
dictionaryValue.setCreatedOn(new Date());
dictionaryValue.setUpdatedOn(new Date());
Mockito.when(dictionaryValueRepo.findById(1).get()).thenReturn(dictionaryValue);
assertThat(dictionaryService.getDictionaryValueListById(1)).isEqualTo(dictionaryValue);
}
Service.java
public DictionaryValue getDictionaryValueListById(int id) {
return dictionaryValueRepo.findById(id).get();
}
Repo.java
#Repository
public interface DictionaryValueRepo extends JpaRepository<DictionaryValue, Integer> {
}
I am getting no such value present again and again on executing test case in testclass.java. I don't know why? but when I am running my service method from the controller it is working as expected - fetching records from the database but not working in a test case.
Your test should be like this and please check out the naming. You need to Mock the step findId() befor the `get().
#InjectMocks
Service cut;
#Mock
DictionaryValueRepo dictionaryValueRepoMock;
// Can skipped by adding a #RunWith... on Testclass
#Before
public init() {
Mockito.initMocks(this);
}
#Test
public void testgetDictionaryValueListById() {
// Prepare Data
final int testId = 1;
DictionaryValue dictionaryValue = new DictionaryValue();
dictionaryValue.setId(testId);
dictionaryValue.setValueName("Test Dictionary Value");
dictionaryValue.setValueKey("12345678");
dictionaryValue.setStatus("Active");
dictionaryValue.setCreatedOn(new Date());
dictionaryValue.setUpdatedOn(new Date());
// config mocking
Mockito.when(dictionaryValueRepo.findById(testId)).thenReturn(<VALUE>);
Mockito.when(dictionaryValueRepo.findById(testId).get()).thenReturn(dictionaryValue);
// Call yout method for Testing
cut.getDictionaryValueListById(testId);
// verifies (if wanted) + assertions....
}
I concur with LenglBoy, so the right answer should be given to him.
The thing you need to be careful is what "VALUE" means in this line:
Mockito.when(dictionaryValueRepo.findById(testId)).thenReturn(VALUE);
The findById returns an Optional, so that is what you should build and pass to Mockito. Something like this:
Mockito.when(dictionaryValueRepo.findById(testId))
.thenReturn(Optional.ofNullable(dictionaryValue));
And for a scenario where the id does not exists in BD, passing Optional.empty() should be good enough.

How to arrange and assert MustBeCalled for property setter in JustMock

I have a mocked class with a property that has a get and set. My code under test calls the setter to assign a connection string value. My test code mocks the class that contains the property and I add MustBeCalled when I arrange the mock.
ViewModel Code:
public class ClientViewModel
{
private readonly IMgmtDataProvider dataProvider;
public ClientViewModel(IMgmtDataProvider dataProvider)
{
this.dataProvider = dataProvider;
}
private string clientConnectionString;
public string ClientConnectionString
{
get { return clientConnectionString; }
set
{
clientConnectionString = value;
if (dataProvider != null)
dataProvider.ClientConnectionString = value;
}
}
}
Test Code:
//Arrange
const string connectionString = "THIS IS MY CONNECTIONSTRING";
var mockedDataProvider = Mock.Create<IMgmtDataProvider>();
Mock.Arrange(() => mockedDataProvider.ClientConnectionString).MustBeCalled();
//Act
var testViewModel = new ClientViewModel(mockedDataProvider);
testViewModel.ClientConnectionString = connectionString;
//Assert
var callCount = Mock.GetTimesCalled(() => mockedDataProvider.ClientConnectinString);
Assert.IsTrue(callCount > 0);
my Mock.Arrange(...).MustBeCalled(); appears to be applied to the getter, not the setter. So, when I call Mock.GetTimesCalled(...), it returns 0. I need to apply the MustBeCalled to the setter instead of the getter. I want to assure the dataprovider's connectionstring is getting set when the viewmodel's connection string gets set. How do I tell JustMock to track how many times a mocked setter is called?
Setters are arranged using the Mock.ArrangeSet() method, like so:
Mock.ArrangeSet(() => mockedDataProvider.ClientConnectionString = Arg.AnyString).MustBeCalled();
....
Mock.Assert(mockedDataProvider); // assert all expectations on this mock
You can also use Mock.AssertSet() as an alternative to the ArrangeSet().MustBeCalled() combo.
And finally, there's the Mock.GetTimesSetCalled() method for getting the number of times that a setter was called.
Check out the documentation on property mocking for examples.

nunit test case- Verify edited note is correct

In the example below, I'm attempting to test that the notes text is changed. Is the Assert.AreEqual(note.Text, text); correct?
[TestMethod()]
public void CreateNoteTest_Pass()
{
HomeController target = new HomeController(); // TODO: Initialize to an appropriate value
var note = new NotePM();
string text = "This is my test note" + DateTime.Now;
note.Text = text;
int id = note.NoteId;
note.CreatedByUserName = Membership.GetUser("danielle").UserName;
ActionResult actual;
actual = target.Create(note);
Assert.AreNotEqual(id, note.NoteId);
Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
Assert.AreEqual(note.Text, text);
}
Here's one take on this:
[TestMethod()]
public void EnsureCreateNoteChangesNoteText()
{
string text = "This is my test note" + DateTime.Now;
var note = new NotePM()
{
Text = text;
CreatedByUserName = "danielle";
};
int id = note.NoteId;
ActionResult actual;
HomeController target = new HomeController();
actual = target.Create(note);
Assert.AreNotEqual(id, note.NoteId, "note.NoteID must be assigned by the controller");
Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
Assert.AreNotEqual(text, note.Text, "note.Text must be changed by the controller");
}
Assert.AreNotEqual() is used to check for inequality (and there is a string overload which does a value comparison)
With the asserts which take 2 values, these should be Assert.xxx(Expected, Actual) otherwise the failure message is inverted.
Unit tests should isolate the system under test as far as possible (HomeController in this example). If HomeController is dependent on asp.net Membership ideally, you should inject this to the controller in the constructor to ensure it can be mocked. This way you can ensure that the unit test runs without the need to prep database data, setup connections from the Unit Test runner, etc.

Using Moq to mock a repository that returns a value

How do I set up my test method on that mocks a repository which accepts an object?
This is what I have so far:
Service.cs
public int AddCountry(string countryName)
{
Country country = new Country();
country.CountryName = countryName;
return geographicsRepository.SaveCountry(country).CountryId;
}
test.cs
[Test]
public void Insert_Country()
{
//Setup
var geographicsRepository = new Mock<IGeographicRepository>();
geographicsRepository.Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))); //How do I return a 1 here?
GeographicService geoService = new GeographicService(geographicsRepository.Object);
int id = geoService.AddCountry("Jamaica");
Assert.AreEqual(1, id);
}
SaveCountry(Country country); returns an int.
I need to do 2 things:
First test, I need to tell the setup to return an int of 1.
I need to create a second test Insert_Duplicate_Country_Throws_Exception(). In my Setup, how do I tell the repository to throw an error when I do:
int id = geoService.AddCountry("Jamaica");
int id = geoService.AddCountry("Jamaica");
Framework:
NUnit.
Moq.
ASP.NET MVC - repository pattern.
Your first test should look something like this:
[Test]
public void Insert_Country()
{
Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
GeographicService geoService = new GeographicService(geographicsRepository.Object);
// Setup Mock
geographicsRepository
.Setup(x => x.SaveCountry(It.IsAny<Country>()))
.Returns(1);
var id = geoService.AddCountry("Jamaica");
Assert.IsInstanceOf<Int32>(id);
Assert.AreEqual(1, id);
geographicsRepository.VerifyAll();
}
The second test should look like this:
[Test]
public void Insert_Duplicate_Country_Throws_Exception()
{
Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
GeographicService geoService = new GeographicService(geographicsRepository.Object);
// Setup Mock
geographicsRepository
.Setup(x => x.SaveCountry(It.IsAny<Country>()))
.Throws(new MyException());
try
{
var id = geoService.AddCountry("Jamaica");
Assert.Fail("Exception not thrown");
}
catch (MyException)
{
geographicsRepository.VerifyAll();
}
}
I think maybe you are slightly misunderstanding the purpose of testing with mocks in the two scenarios you have supplied.
In the first scenario, you wish to test that 1 is returned when you pass in "Jamaica". This is not a mock test case but a test case for real behaviour as you wish to test a specific input against an expected output i.e. "Jamaica" -> 1. In this situation mocking is more useful to ensure that internally your service calls SaveCountry on the repository with the expected country, and that it returns the value from the call.
Setting up your "SaveCountry" case and then calling "VerifyAll" on your mock is the key. This will assert that "SaveCountry" was indeed called with country "Jamaica", and that the expected value is returned. In this way you have confidence that your service is wired up to your repository as expected.
[Test]
public void adding_country_saves_country()
{
const int ExpectedCountryId = 666;
var mockRepository = new Mock<IGeographicRepository>();
mockRepository.
Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))).
Returns(ExpectedCountryId);
GeographicService service= new GeographicService(mockRepository.Object);
int id = service.AddCountry(new Country("Jamaica"));
mockRepo.VerifyAll();
Assert.AreEqual(ExpectedCountryId, id, "Expected country id.");
}
In the second scenario you wish to test that an exception is raised when you attempt to add a duplicate country. There's not much point in doing this with a mock as all you will test is that your mock has behaviour when adding duplicates, not your real implementation.